constitution firewall

This commit is contained in:
Danilo Reyes
2026-04-01 23:59:58 -06:00
parent 4eeed32002
commit 78c37081d7
7 changed files with 129 additions and 57 deletions

View File

@@ -1,50 +1,101 @@
# [PROJECT_NAME] Constitution
<!-- Example: Spec Constitution, TaskFlow Constitution, etc. -->
<!--
Sync Impact Report
- Version change: template -> 1.0.0
- Modified principles:
- Template Principle 1 -> I. Constitution Authority
- Template Principle 2 -> II. Module and Host Boundaries
- Template Principle 3 -> III. Host-Local Firewall Ownership
- Template Principle 4 -> IV. Nix Structure and Ordering
- Template Principle 5 -> V. Secure Host and Secrets Discipline
- Added sections:
- Repository Constraints
- Delivery Workflow
- Removed sections:
- None
- Templates requiring updates:
- ✅ updated `.specify/templates/plan-template.md`
- ✅ updated `.specify/templates/spec-template.md`
- ✅ updated `.specify/templates/tasks-template.md`
- ✅ updated `docs/constitution.md`
- ✅ updated `docs/reference/index.md`
- ✅ updated `specs/001-ai-docs/research.md`
- ✅ no `.specify/templates/commands/*.md` files present
- Follow-up TODOs:
- None
-->
# NixOS Repository Constitution
## Core Principles
### [PRINCIPLE_1_NAME]
<!-- Example: I. Library-First -->
[PRINCIPLE_1_DESCRIPTION]
<!-- Example: Every feature starts as a standalone library; Libraries must be self-contained, independently testable, documented; Clear purpose required - no organizational-only libraries -->
### I. Constitution Authority
This constitution is the source of truth for Speckit-driven planning and
implementation work in this repository. Plans, specs, tasks, and runtime
guidance MUST align with it. When another document conflicts with this
constitution, the conflicting document MUST be updated in the same change set
or the conflict MUST be recorded in `specs/001-ai-docs/research.md`.
### [PRINCIPLE_2_NAME]
<!-- Example: II. CLI Interface -->
[PRINCIPLE_2_DESCRIPTION]
<!-- Example: Every library exposes functionality via CLI; Text in/out protocol: stdin/args → stdout, errors → stderr; Support JSON + human-readable formats -->
### II. Module and Host Boundaries
Code MUST live in the directory that owns the behavior. Shared feature logic
belongs under `modules/`; host-specific assembly belongs under `hosts/<name>/`;
factory helpers belong under `modules/factories/`; repo-wide shared options
belong under `modules/modules.nix` or the relevant shared module. New behavior
MUST NOT be placed in an unrelated host or module file for convenience.
### [PRINCIPLE_3_NAME]
<!-- Example: III. Test-First (NON-NEGOTIABLE) -->
[PRINCIPLE_3_DESCRIPTION]
<!-- Example: TDD mandatory: Tests written → User approved → Tests fail → Then implement; Red-Green-Refactor cycle strictly enforced -->
### III. Host-Local Firewall Ownership
Any host that contains firewall rules MUST keep firewall-related logic in
`hosts/<name>/firewall.nix`. Host `configuration.nix` files MAY import that
file, but MUST NOT become the long-term home for firewall rule definitions,
NAT rules, nftables tables, forward-port rules, or other firewall-specific
logic. Firewall changes in specs, plans, and task lists MUST reference the
host-local `firewall.nix` path explicitly.
### [PRINCIPLE_4_NAME]
<!-- Example: IV. Integration Testing -->
[PRINCIPLE_4_DESCRIPTION]
<!-- Example: Focus areas requiring integration tests: New library contract tests, Contract changes, Inter-service communication, Shared schemas -->
### IV. Nix Structure and Ordering
Nix code MUST preserve grouped parents when they have multiple children and
MUST flatten only single-child chains. Siblings that share a parent MUST live
under one parent block instead of being split across disconnected assignments.
Within module bodies, `options` MUST appear before `config`. Within attribute
sets, `inherit` statements MUST come first, then boolean leaves, then other
leaf assignments, then nested attribute sets.
### [PRINCIPLE_5_NAME]
<!-- Example: V. Observability, VI. Versioning & Breaking Changes, VII. Simplicity -->
[PRINCIPLE_5_DESCRIPTION]
<!-- Example: Text I/O ensures debuggability; Structured logging required; Or: MAJOR.MINOR.BUILD format; Or: Start simple, YAGNI principles -->
### V. Secure Host and Secrets Discipline
Secret-dependent behavior MUST stay behind `config.my.secureHost`. Secrets MUST
live in the appropriate `secrets/*.yaml` file by purpose, and hosts marked
non-secure MUST avoid secret-dependent services and secret loading. Proxy-only
or network-only changes MUST still respect secret ownership, secure-host
gating, and host-local boundaries.
## [SECTION_2_NAME]
<!-- Example: Additional Constraints, Security Requirements, Performance Standards, etc. -->
## Repository Constraints
[SECTION_2_CONTENT]
<!-- Example: Technology stack requirements, compliance standards, deployment policies, etc. -->
- Host definitions live in `hosts/<name>/configuration.nix` with optional
imports such as `hosts/<name>/firewall.nix` and `hosts/<name>/toggles.nix`.
- Module categories remain `apps`, `dev`, `scripts`, `servers`, `services`,
`shell`, `websites`, `network`, `users`, and `nix`, with feature directories
preferred over new flat modules.
- Service ports intrinsic to a server module SHOULD live with that module;
miscellaneous shared ports SHOULD live in `my.ports`.
- Firewall rules, NAT, nftables tables, and forward-port declarations for a
host MUST be reviewed as one unit inside that host's `firewall.nix`.
## [SECTION_3_NAME]
<!-- Example: Development Workflow, Review Process, Quality Gates, etc. -->
## Delivery Workflow
[SECTION_3_CONTENT]
<!-- Example: Code review requirements, testing gates, deployment approval process, etc. -->
- Every plan MUST include a constitution check that validates module ownership,
host ownership, secure-host impact, and whether firewall work belongs in
`hosts/<name>/firewall.nix`.
- Every spec that changes networking or exposure MUST state which host owns the
change and which firewall file is affected.
- Every task list that includes firewall work MUST name the concrete
`hosts/<name>/firewall.nix` path.
- Runtime guidance docs that describe repository structure MUST be updated when
host boundary rules change.
## Governance
<!-- Example: Constitution supersedes all other practices; Amendments require documentation, approval, migration plan -->
[GOVERNANCE_RULES]
<!-- Example: All PRs/reviews must verify compliance; Complexity must be justified; Use [GUIDANCE_FILE] for runtime development guidance -->
This constitution supersedes conflicting Speckit planning assumptions for this
repository. Amendments MUST be made in the same change set as any dependent
template or runtime guidance updates. Versioning follows semantic versioning:
MAJOR for incompatible governance changes or principle removals, MINOR for new
principles or materially expanded rules, PATCH for clarifications that do not
change required behavior. Compliance review is mandatory for every plan, spec,
and tasks artifact that claims alignment with this constitution.
**Version**: [CONSTITUTION_VERSION] | **Ratified**: [RATIFICATION_DATE] | **Last Amended**: [LAST_AMENDED_DATE]
<!-- Example: Version: 2.1.1 | Ratified: 2025-06-13 | Last Amended: 2025-07-16 -->
**Version**: 1.0.0 | **Ratified**: 2026-04-01 | **Last Amended**: 2026-04-01

View File

@@ -31,7 +31,12 @@
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
[Gates determined based on constitution file]
- Confirm each change lives in the directory that owns the behavior.
- Confirm shared logic stays in `modules/` and host-specific assembly stays in
`hosts/<name>/`.
- Confirm any firewall, NAT, nftables, or port-forwarding work is scoped to
`hosts/<name>/firewall.nix` for the affected host.
- Confirm any secret-dependent behavior respects `config.my.secureHost`.
## Project Structure

View File

@@ -89,11 +89,13 @@
- **FR-003**: Users MUST be able to [key interaction, e.g., "reset their password"]
- **FR-004**: System MUST [data requirement, e.g., "persist user preferences"]
- **FR-005**: System MUST [behavior, e.g., "log all security events"]
- **FR-006**: If the feature changes host firewall behavior, the spec MUST name
the affected `hosts/<name>/firewall.nix` file explicitly.
*Example of marking unclear requirements:*
- **FR-006**: System MUST authenticate users via [NEEDS CLARIFICATION: auth method not specified - email/password, SSO, OAuth?]
- **FR-007**: System MUST retain user data for [NEEDS CLARIFICATION: retention period not specified]
- **FR-007**: System MUST authenticate users via [NEEDS CLARIFICATION: auth method not specified - email/password, SSO, OAuth?]
- **FR-008**: System MUST retain user data for [NEEDS CLARIFICATION: retention period not specified]
### Key Entities *(include if feature involves data)*

View File

@@ -17,6 +17,8 @@ description: "Task list template for feature implementation"
- **[P]**: Can run in parallel (different files, no dependencies)
- **[Story]**: Which user story this task belongs to (e.g., US1, US2, US3)
- Include exact file paths in descriptions
- If firewall behavior changes, tasks MUST reference `hosts/<name>/firewall.nix`
instead of only `hosts/<name>/configuration.nix`
## Path Conventions
@@ -68,6 +70,8 @@ Examples of foundational tasks (adjust based on your project):
- [ ] T007 Create base models/entities that all stories depend on
- [ ] T008 Configure error handling and logging infrastructure
- [ ] T009 Setup environment configuration management
- [ ] T010 If networking changes, update the affected `hosts/<name>/firewall.nix`
and import wiring in `hosts/<name>/configuration.nix`
**Checkpoint**: Foundation ready - user story implementation can now begin in parallel
@@ -83,17 +87,17 @@ Examples of foundational tasks (adjust based on your project):
> **NOTE: Write these tests FIRST, ensure they FAIL before implementation**
- [ ] T010 [P] [US1] Contract test for [endpoint] in tests/contract/test_[name].py
- [ ] T011 [P] [US1] Integration test for [user journey] in tests/integration/test_[name].py
- [ ] T011 [P] [US1] Contract test for [endpoint] in tests/contract/test_[name].py
- [ ] T012 [P] [US1] Integration test for [user journey] in tests/integration/test_[name].py
### Implementation for User Story 1
- [ ] T012 [P] [US1] Create [Entity1] model in src/models/[entity1].py
- [ ] T013 [P] [US1] Create [Entity2] model in src/models/[entity2].py
- [ ] T014 [US1] Implement [Service] in src/services/[service].py (depends on T012, T013)
- [ ] T015 [US1] Implement [endpoint/feature] in src/[location]/[file].py
- [ ] T016 [US1] Add validation and error handling
- [ ] T017 [US1] Add logging for user story 1 operations
- [ ] T013 [P] [US1] Create [Entity1] model in src/models/[entity1].py
- [ ] T014 [P] [US1] Create [Entity2] model in src/models/[entity2].py
- [ ] T015 [US1] Implement [Service] in src/services/[service].py (depends on T013, T014)
- [ ] T016 [US1] Implement [endpoint/feature] in src/[location]/[file].py
- [ ] T017 [US1] Add validation and error handling
- [ ] T018 [US1] Add logging for user story 1 operations
**Checkpoint**: At this point, User Story 1 should be fully functional and testable independently
@@ -107,15 +111,15 @@ Examples of foundational tasks (adjust based on your project):
### Tests for User Story 2 (OPTIONAL - only if tests requested) ⚠️
- [ ] T018 [P] [US2] Contract test for [endpoint] in tests/contract/test_[name].py
- [ ] T019 [P] [US2] Integration test for [user journey] in tests/integration/test_[name].py
- [ ] T019 [P] [US2] Contract test for [endpoint] in tests/contract/test_[name].py
- [ ] T020 [P] [US2] Integration test for [user journey] in tests/integration/test_[name].py
### Implementation for User Story 2
- [ ] T020 [P] [US2] Create [Entity] model in src/models/[entity].py
- [ ] T021 [US2] Implement [Service] in src/services/[service].py
- [ ] T022 [US2] Implement [endpoint/feature] in src/[location]/[file].py
- [ ] T023 [US2] Integrate with User Story 1 components (if needed)
- [ ] T021 [P] [US2] Create [Entity] model in src/models/[entity].py
- [ ] T022 [US2] Implement [Service] in src/services/[service].py
- [ ] T023 [US2] Implement [endpoint/feature] in src/[location]/[file].py
- [ ] T024 [US2] Integrate with User Story 1 components (if needed)
**Checkpoint**: At this point, User Stories 1 AND 2 should both work independently
@@ -129,14 +133,14 @@ Examples of foundational tasks (adjust based on your project):
### Tests for User Story 3 (OPTIONAL - only if tests requested) ⚠️
- [ ] T024 [P] [US3] Contract test for [endpoint] in tests/contract/test_[name].py
- [ ] T025 [P] [US3] Integration test for [user journey] in tests/integration/test_[name].py
- [ ] T025 [P] [US3] Contract test for [endpoint] in tests/contract/test_[name].py
- [ ] T026 [P] [US3] Integration test for [user journey] in tests/integration/test_[name].py
### Implementation for User Story 3
- [ ] T026 [P] [US3] Create [Entity] model in src/models/[entity].py
- [ ] T027 [US3] Implement [Service] in src/services/[service].py
- [ ] T028 [US3] Implement [endpoint/feature] in src/[location]/[file].py
- [ ] T027 [P] [US3] Create [Entity] model in src/models/[entity].py
- [ ] T028 [US3] Implement [Service] in src/services/[service].py
- [ ] T029 [US3] Implement [endpoint/feature] in src/[location]/[file].py
**Checkpoint**: All user stories should now be independently functional

View File

@@ -11,6 +11,7 @@
- Module auto-import: `modules/modules.nix` auto-imports legacy flat modules under `modules/apps`, `modules/dev`, `modules/scripts`, `modules/servers`, `modules/services`, `modules/shell`, `modules/websites`, and `modules/network`, excluding `librewolf.nix`, and also discovers nested `nixos.nix` files under those trees. `config/base.nix` registers `modules/home-manager.nix` as a Home Manager shared module, which discovers nested `home.nix` files under `modules/` for every Home Manager user. Factories live in `modules/factories/` (`mkserver`, `mkscript`), and shared options are in `modules/nix` and `modules/users`.
- Home Manager helper layer: Common Home Manager wrapper logic belongs in `parts/core.nix` helpers under `inputs.self.lib` when it is repeated across multiple `home.nix` modules. Current helpers include split-loader support plus `hmModule`, `hmShellType`, and `hmOnlyUser` for shared enablement and shell-selection patterns.
- Hosts and toggles: Host definitions live in `hosts/<name>/configuration.nix` with host-specific toggles in `hosts/<name>/toggles.nix`. The `my` namespace carries toggles for apps/dev/scripts/services/shell, feature flags like `enableProxy` and `enableContainers`, and per-host `interfaces` and `ips` maps.
- Host-local firewall ownership: Hosts that define firewall rules MUST keep firewall-related logic in `hosts/<name>/firewall.nix`, imported from `hosts/<name>/configuration.nix` as needed. Host `configuration.nix` files are the assembly point, not the long-term home for firewall rule definitions.
- Standalone Home Manager hosts: Home-only hosts may live under `hosts/<name>/home.nix` with `hosts/<name>/toggles.nix`, and should only enable modules that have a `home.nix` surface or are otherwise known to be Home Manager-compatible on that platform.
- Port assignment: Service ports should live with the service module when the port is intrinsic to a server definition under `modules/servers/`. Miscellaneous or host-specific ports that do not belong to a server module should be centralized in `my.ports` in `modules/modules.nix` and referenced via `config.my.ports.*` (use `toString config.my.ports.*` where a string is required).
- Main server and proxies: `my.mainServer` selects the host that should serve traffic by default (default `vps`). Reverse proxies use helpers in `parts/core.nix` (`proxy`, `proxyReverse`, `proxyReverseFix`, `proxyReversePrivate`) and pick IPs from `my.ips` plus the hostName/ip set by `mkserver` options. Nginx defaults to `proxyReverse` for any server with `enableProxy = true` unless `useDefaultProxy = false` or the server is listed in the Fix/Private proxy lists.
@@ -21,6 +22,7 @@
- Minimize comments; prefer clear naming and shared helpers (`modules/factories/mkserver.nix`, `modules/factories/mkscript.nix`) to avoid duplication.
- Use business-level, technology-agnostic language in AI docs; reserve implementation detail for module code.
- Nix structure: flatten single-child attribute sets into their full path; keep multi-child sets nested for readability; merge siblings under a shared parent; flatten the shallowest subtree first to reduce indentation without losing clarity.
- Parent ownership rule: when a parent has multiple children, keep them grouped under that parent instead of splitting them across scattered assignments. Flatten only single-child chains.
- Nix attribute ordering: prefer `options` before `config` in module bodies; inside attribute sets keep `inherit` statements first, then boolean leaf assignments, then other leaf assignments, then nested attribute sets; when simple leaves and nested children share a parent, place the simple leaves first.
```nix
config.services.jellyfin.enable = true; # preferred single-leaf form
@@ -78,6 +80,7 @@ config.services = {
## Maintenance Triggers and Update Process
- Triggers: New factory/helper, new module category, new host, new toggle set, new proxy rule, new secret category/file, change to `my.mainServer` or `my.ips`, stylix scheme changes, or new auto-import filters/import trees.
- Triggers: New factory/helper, new module category, new host, new toggle set, new proxy rule, new host firewall ownership rule or `hosts/<name>/firewall.nix` layout change, new secret category/file, change to `my.mainServer` or `my.ips`, stylix scheme changes, or new auto-import filters/import trees.
- Update flow: (1) Amend the relevant module or toggle files; (2) Update `docs/constitution.md` for rules/terminology changes; (3) Update playbooks under `docs/playbooks/` affected by the change; (4) Update `docs/reference/index.md` for navigation paths; (5) Note the decision in `specs/001-ai-docs/research.md` and refresh `quickstart.md` if discoverability shifts.
- Validation: Confirm discoverability within two clicks (constitution → reference map/playbook), secrets map completeness, and alignment with success criteria SC-001SC-004.

View File

@@ -39,6 +39,7 @@
## Hosts and Roles
- NixOS configs: `hosts/<name>/configuration.nix` with toggles in `hosts/<name>/toggles.nix`.
- Firewall-bearing hosts: keep firewall logic in `hosts/<name>/firewall.nix` and import it from `hosts/<name>/configuration.nix`.
- Standalone Home Manager configs: `hosts/<name>/home.nix` with optional toggles in `hosts/<name>/toggles.nix`.
- Active NixOS hosts: `workstation`, `server`, `miniserver`, `galaxy`, `emacs`, `vps`.
- Active Home Manager hosts: `mac`.
@@ -64,6 +65,7 @@
- Default proxying: any server with `enableProxy = true` gets a `proxyReverse` vhost unless `useDefaultProxy = false` or it is listed in `proxyReverseFix` / `proxyReversePrivate`.
- Main server selection: `my.mainServer` chooses where services live by default (default `vps`); `mkserver` sets `isLocal` based on this and picks IPs from `my.ips`.
- Firewall generation: `inputs.self.lib.generateFirewallPorts` combines static ports, additional ports, and service ports from `my.servers` (excluding native firewall services). Use `my.network.firewall` settings and `getServicesWithNativeFirewall` to derive open ports.
- Host firewall placement: host-specific firewall rules, NAT, nftables tables, and forward-port definitions belong in `hosts/<name>/firewall.nix`.
## Secrets Map
- Files and purposes:

View File

@@ -54,3 +54,8 @@
- **Decision**: Standardize Nix structure so single-child attribute sets are flattened into dotted attrpaths, siblings that share a parent are merged into one nested attribute set, simple leaf assignments appear before nested attribute sets, `inherit` statements appear first within a set, boolean leaves appear before other leaves, and module bodies place `options` before `config`.
- **Rationale**: This keeps modules scan-friendly, reduces unnecessary indentation, and makes the high-signal contract (`options`) appear before implementation (`config`) consistently across the repo.
- **Alternatives considered**: (a) Leave structure to formatter defaults only (rejected: formatters do not enforce these semantic grouping rules); (b) prefer fully flattened attrpaths everywhere (rejected: harms readability once a parent has multiple children); (c) keep `config` before `options` when it was written first (rejected: makes module interfaces harder to scan).
## Decision 12 (2026-04-01): Host-local firewall files
- **Decision**: Any host that owns firewall rules MUST keep firewall-related logic in `hosts/<name>/firewall.nix`, with `hosts/<name>/configuration.nix` importing that file rather than accumulating the firewall logic inline.
- **Rationale**: Firewall behavior is a distinct host concern that becomes hard to review and maintain when mixed into general host assembly. A dedicated `firewall.nix` preserves ownership boundaries and makes networking changes easier to audit.
- **Alternatives considered**: (a) Keep firewall rules inline in `configuration.nix` (rejected: mixes host assembly with a dense, security-sensitive subsystem); (b) centralize all firewall logic under `modules/network/` (rejected: hides host-specific rule ownership and deployment context).