Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
553c25e
Refactor API token introspection credentials
aidankhogg Jun 26, 2026
a573362
Harden import snapshot validation
aidankhogg Jun 26, 2026
81f1318
Merge branch 'dev/alpha' into codex/refactor-api-auth-introspection-flow
aidankhogg Jun 26, 2026
aedaf11
Merge branch 'dev/alpha' into codex/harden-/api/v1/import-endpoint
aidankhogg Jun 26, 2026
efae01d
Fix AND deduplication key, add 404 for missing AND, fix reheal loop f…
claude Jun 27, 2026
e6aeb59
Add phase event queues to initial migration
aidankhogg Jun 28, 2026
27fb3b5
Update event queue documentation
aidankhogg Jun 28, 2026
7ba9e39
Add explicit DLQ queue mapping helper
aidankhogg Jun 28, 2026
d3e9b93
feat: an explicit DLQ mapping and helper & use of it in API/CLI/PGMQ…
aidankhogg Jun 28, 2026
4d15f0b
Add shared database migration service
aidankhogg Jun 28, 2026
65aa848
Merge branch 'dev/alpha' into codex/create-shared-migration-module
aidankhogg Jun 28, 2026
bf4aa82
feat: shared database migration service
aidankhogg Jun 28, 2026
dfe2932
fix: Added phase event queues to initial migration
aidankhogg Jun 28, 2026
26f5b61
feat: Document PRIMARY_QUEUES as source of truth and list 11 primary…
aidankhogg Jun 28, 2026
5a92bc2
Use Queue enum for PGMQ call sites
aidankhogg Jun 28, 2026
2d6a69a
Use initial migration for integration pgmq setup
aidankhogg Jun 28, 2026
646e088
Add migration ledger tracking
aidankhogg Jun 28, 2026
d102e23
Merge branch 'dev/alpha' into codex/add-migration-ledger-table-and-up…
aidankhogg Jun 28, 2026
1dca946
feat: migration ledger tracking
aidankhogg Jun 28, 2026
87a6efc
fix: Use initial migration for integration pgmq setup
aidankhogg Jun 28, 2026
9f21364
Merge branch 'dev/alpha' into codex/update-pgmq-call-sites-to-use-queue
aidankhogg Jun 28, 2026
12cae22
fix: Use Queue enum for PGMQ call sites and add DLQ helper
aidankhogg Jun 28, 2026
91e5d97
Make pgmq queue creation idempotent
aidankhogg Jun 28, 2026
c81dc97
Add migration CLI commands
aidankhogg Jun 28, 2026
af85555
Merge branch 'dev/alpha' into codex/refactor-api-auth-introspection-flow
aidankhogg Jun 28, 2026
8ee58be
fix: Refactored API auth introspection credentials
aidankhogg Jun 28, 2026
d4decaa
Merge branch 'dev/alpha' into codex/harden-/api/v1/import-endpoint
aidankhogg Jun 28, 2026
4dbf7cb
fix: Hardend /api/v1/import: schema, spec validation, and phase checks
aidankhogg Jun 28, 2026
42e288f
Merge branch 'dev/alpha' into codex/update-pgmq-queue-creation-for-id…
aidankhogg Jun 28, 2026
d71f17b
fix: Made initial pgmq queue creation idempotent
aidankhogg Jun 28, 2026
8577cb6
Merge branch 'dev/alpha' into codex/add-migrate-command-group-in-nete…
aidankhogg Jun 28, 2026
44cd627
feat: `netengine migrate` CLI commands and shared MigrationService
aidankhogg Jun 28, 2026
e659312
fix: AND dedup key, add 404 for missing AND, fix reheal loop filter
aidankhogg Jun 28, 2026
0815a25
Fail CLI boot on migration errors
aidankhogg Jun 28, 2026
4527805
fix: Treat migration failures as fatal in `netengine up`
aidankhogg Jun 28, 2026
3d4d8fa
Enhance migration failure semantics
aidankhogg Jun 28, 2026
64bc96b
docs: add migration rollback guidance
aidankhogg Jun 28, 2026
8b5781e
Add pgmq migration integration tests
aidankhogg Jun 28, 2026
6169919
Merge branch 'dev/alpha' into codex/enhance-migration-service-for-par…
aidankhogg Jun 28, 2026
3fb9143
feat: enhanced the MigrationService with per-file transactions and pa…
aidankhogg Jun 28, 2026
fd3c44d
docs: add migration rollback & pgmq recovery guidance
aidankhogg Jun 28, 2026
5a96e56
Constrain cryptography below 49
aidankhogg Jun 28, 2026
6152adc
Fix CLI import after install
aidankhogg Jun 28, 2026
89a8016
Merge branch 'dev/alpha' into codex/fix-poetry-installation-issue-wit…
aidankhogg Jun 28, 2026
9749990
fix: Constrained cryptography below 49
aidankhogg Jun 28, 2026
1ce138c
Add feature state metadata for PKI spec fields
aidankhogg Jun 29, 2026
a156e16
Merge branch 'dev/alpha' into codex/add-integration-tests-for-migrati…
aidankhogg Jun 29, 2026
ac23290
feat: feature state metadata for PKI spec fields
aidankhogg Jun 29, 2026
396b446
Validate feature-state gated spec fields
aidankhogg Jun 29, 2026
c3a600d
Add shared event emission failure diagnostics
aidankhogg Jun 29, 2026
b79d5b7
Validate DLQ replay queue names
aidankhogg Jun 29, 2026
5d1f94e
chore: pgmq migration integration tests and `migrate` CLI
aidankhogg Jun 29, 2026
76da488
Merge pull request #91 from Forebase/codex/update-replay_dlq-with-que…
aidankhogg Jun 29, 2026
f765754
Merge branch 'dev/alpha' into codex/extend-feature-state-validator-in…
aidankhogg Jun 29, 2026
5a4bc40
feat: shared event emitter and diagnostics for PGMQ send failures
aidankhogg Jun 29, 2026
7c59f18
feat: feature-state validator for spec fields (reject unsupported, w…
aidankhogg Jun 29, 2026
e7a0aa5
test: keep integration pgmq setup on migrations
aidankhogg Jun 29, 2026
b7a6051
Keep integration pgmq setup on initial migration
aidankhogg Jun 29, 2026
430122f
Document alpha feature support matrix
aidankhogg Jun 29, 2026
64f8835
Disable DNSSEC by default in specs
aidankhogg Jun 29, 2026
2601049
Add spec validation CLI command
aidankhogg Jun 29, 2026
d7c1ac3
chore: Disabled unsupported DNSSEC defaults
aidankhogg Jun 29, 2026
1aae041
feat: `validate` CLI command with --explain and shared spec loading
aidankhogg Jun 29, 2026
f0bc6ad
Type PGMQ client results
aidankhogg Jun 29, 2026
bb51756
docs: alpha spec support matrix and update gap analysis docs
aidankhogg Jun 29, 2026
d1695e4
Add typed event payload factories
aidankhogg Jun 29, 2026
ca10e95
Type PGMQ client results
aidankhogg Jun 29, 2026
d1bdc69
Add CLI doctor preflight command
aidankhogg Jun 29, 2026
573289b
feat: typed event payloads and factory layer; migrate registry and d…
aidankhogg Jun 29, 2026
7fe1d1d
feat: `netengine doctor` CLI preflight command
aidankhogg Jun 29, 2026
fadf7fd
Type runtime phase outputs
aidankhogg Jun 29, 2026
086f386
Merge branch 'dev/alpha' into codex/add-typed-output-structures-in-st…
aidankhogg Jun 29, 2026
8782b6d
fix: TypedDict phase outputs for RuntimeState and tighten related st…
aidankhogg Jun 29, 2026
7445887
Add Docker adapter protocol for handlers
aidankhogg Jun 29, 2026
a874fd8
Add host-readiness preflight layer
aidankhogg Jun 29, 2026
27cc777
feat: DockerAdapterProtocol and migrate handlers to use it
aidankhogg Jun 29, 2026
5f4f871
feat: host-readiness preflight layer and make CLI doctor a thin wrapper
aidankhogg Jun 29, 2026
fe298ce
docs: add alpha golden paths
aidankhogg Jun 29, 2026
6e99a9d
Harden alpha state compatibility
aidankhogg Jun 29, 2026
75aa71c
docs: add alpha golden paths
aidankhogg Jun 29, 2026
1590d73
feat: Harden alpha state compatibility
aidankhogg Jun 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 91 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,20 @@ cd NetEngine
# 2. Install dependencies
poetry install

# 3. Start local Postgres + pgmq (includes pgmq extension pre-installed)
docker compose up -d db
# 3. Verify host prerequisites
poetry run netengine doctor

# 4. Apply migrations
# 4. Start local Postgres + pgmq (includes pgmq extension pre-installed)
docker compose up -d postgres

# 5. Apply migrations
poetry run python -m netengine.utils.run_migrations

# 5. Boot a minimal world
# 6. Boot a minimal world
poetry run netengine up examples/minimal.yaml
```

Check status at any time:
If you only want host/container checks before configuring Postgres, run `poetry run netengine doctor --skip-db`. Check status at any time:

```bash
poetry run netengine status
Expand All @@ -84,6 +87,60 @@ Worlds are defined in YAML. See `examples/` for reference:
| `examples/single-org.yaml` | One organisation with residential AND |
| `examples/dev-sandbox.yaml` | Full dev setup with orgs, ANDs, mail, storage |

### Alpha golden paths

These are the official alpha operator paths. Run them after the Quickstart setup to validate the supported lifecycle.

#### Path A — Minimal smoke world

```bash
poetry run netengine up examples/minimal.yaml
poetry run netengine up examples/minimal.yaml
poetry run netengine status
poetry run netengine diagnose examples/minimal.yaml
poetry run netengine down --dry-run
poetry run netengine down --yes
```

The second `up` proves idempotency.

#### Path B — Single-org world

Uses `examples/single-org.yaml` to prove org identity, DNS delegation, AND profile basics, and registry records.

```bash
poetry run netengine up examples/single-org.yaml
poetry run netengine up examples/single-org.yaml
poetry run netengine status
poetry run netengine diagnose examples/single-org.yaml
poetry run netengine down --dry-run
poetry run netengine down --yes
```

#### Path C — Dev sandbox

Uses `examples/dev-sandbox.yaml` as the feature-rich alpha demo. It is more experimental than Paths A/B if some integrations are still stabilizing.

```bash
poetry run netengine up examples/dev-sandbox.yaml
poetry run netengine up examples/dev-sandbox.yaml
poetry run netengine status
poetry run netengine diagnose examples/dev-sandbox.yaml
poetry run netengine down --dry-run
poetry run netengine down --yes
```

#### Acceptance checklist

- Fresh install works
- Boot completes
- Re-running `up` is idempotent
- `status` is accurate
- `diagnose` explains failures
- `reload` rejects immutable changes
- `down --dry-run` lists resources
- `down --yes` leaves no project-owned Docker resources behind

### Spec composition

Large specs can be split across files:
Expand All @@ -108,6 +165,27 @@ poetry run netengine up spec.yaml --set metadata.name=my-world

---


## Operator migration guidance

Alpha migrations are forward-only unless a migration file includes explicit manual rollback notes. Inspect applied migrations with:

```bash
psql "$NETENGINE_DB_URL" -c "SELECT version, dirty FROM schema_migrations;"
psql "$NETENGINE_DB_URL" -c "SELECT version FROM schema_migrations ORDER BY version DESC LIMIT 1;"
```

The second command identifies the last applied migration. If a migration fails, stop writers, capture the error and current `schema_migrations` state, inspect partially-created objects, and follow that migration's manual recovery notes before retrying. Without explicit rollback notes, restore from backup or rebuild only if the database is disposable. Wiping and reapplying migrations is acceptable for local/dev/CI alpha databases with no durable data; it is unsafe for shared, persistent, staging, production, or customer-like environments without an approved backup/restore plan.

pgmq queue additions should be treated as forward schema changes and should create both the queue and matching `*_dlq` queue. Prefer migrations over manual changes. If a queue must be created manually during alpha recovery, first inspect existing queues and then create both queues explicitly; remove queues only in disposable environments or after confirming no pending/audit messages are needed:

```bash
psql "$NETENGINE_DB_URL" -c "SELECT queue_name FROM pgmq.list_queues() ORDER BY queue_name;"
psql "$NETENGINE_DB_URL" -c "SELECT pgmq.create('new_queue'); SELECT pgmq.create('new_queue_dlq');"
```

See `docs/runbook.md` for the full rollback and recovery procedure.

## Architecture

```
Expand Down Expand Up @@ -137,9 +215,15 @@ poetry run netengine up spec.yaml --set metadata.name=my-world
└─────────────────────────────────────────────────┘
```

**Runtime state** is persisted to `netengines_state.json` after each phase so interrupted runs can resume where they left off.
**Runtime state** is persisted to `netengines_state.json` after each phase so interrupted runs can resume where they left off. The state file carries `schema_version: netengine.runtime_state.v1`; pre-version alpha.1 state files are detected as v1-compatible and stamped on the next save, while unknown future/foreign versions fail closed with instructions to export using the older release or migrate through a compatible release. The file is written atomically with `0600` permissions because it can contain runtime secrets (bootstrap admin password, OIDC client secrets, generated in-world admin passwords, and other phase outputs). Do not commit it, attach it to issues, or copy it into shared logs; use a sanitized support bundle instead.

**Spec compatibility** is tracked in `metadata.schema_version` (default `netengine.spec.v1`). The loader accepts missing schema versions for existing alpha specs, rejects unsupported versions before boot/import, and includes the spec schema in support bundles so alpha.2+ can decide whether an alpha.1 world is safe to restore.

**Support bundles** are produced with `netengine export --out netengine-support-bundle.json` or `GET /api/v1/export`. Bundles include schema metadata, the world spec, phase completion, public CA material, and sanitized phase outputs with secret-looking fields/private PEMs removed. Restore with `netengine import <bundle-file>` or `POST /api/v1/import`; import validates the bundle schema, spec schema compatibility, spec parseability, known phases, phase prerequisites, and required outputs before replacing local runtime state.

**Persistent teardown safety** requires typed confirmation. CLI teardown of a persistent world must pass `netengine down --confirm <world-name>`; the operator API requires both `confirm=true` and `confirmation` equal to the world name. `--yes` is intentionally not enough for persistent destructive operations.

**Events** flow phase-to-phase via pgmq queues: `dns_updates`, `oidc_provisioning`, `and_provisioning`, `inworld_admissions`, `services_admissions`. Each queue has a dead-letter queue (`*_dlq`) for failed messages.
**Events** flow phase-to-phase via pgmq queues defined by `netengine/events/queues.py::PRIMARY_QUEUES`. There are currently 11 primary queues (`dns_updates`, `oidc_provisioning`, `and_provisioning`, `inworld_admissions`, `services_admissions`, `and_admissions`, `pki_cert_rotation_events`, `drift_events`, `world_health`, `gateway_portal_events`, `phase_events`) plus 11 matching dead-letter queues (`*_dlq`) for failed messages.

---

Expand Down
11 changes: 4 additions & 7 deletions compose/compose.test-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ version: '3.8'

services:
postgres-integration:
image: postgres:15
image: ghcr.io/pgmq/pg15-pgmq:latest
container_name: netengine_postgres_integration
environment:
POSTGRES_USER: netengine
Expand Down Expand Up @@ -38,13 +38,10 @@ services:
PGPASSWORD: integration_test_password
command: |
sh -c "
psql -h postgres-integration -U netengine -d netengine_integration -c 'CREATE EXTENSION IF NOT EXISTS pgmq' &&
psql -h postgres-integration -U netengine -d netengine_integration -c 'SELECT pgmq.create_queue(''dns_updates'');' &&
psql -h postgres-integration -U netengine -d netengine_integration -c 'SELECT pgmq.create_queue(''oidc_provisioning'');' &&
psql -h postgres-integration -U netengine -d netengine_integration -c 'SELECT pgmq.create_queue(''and_provisioning'');' &&
psql -h postgres-integration -U netengine -d netengine_integration -c 'SELECT pgmq.create_queue(''inworld_admissions'');' &&
psql -h postgres-integration -U netengine -d netengine_integration -c 'SELECT pgmq.create_queue(''services_admissions'');'
psql -h postgres-integration -U netengine -d netengine_integration -f /migrations/001_initial.sql
"
volumes:
- ../migrations/001_initial.sql:/migrations/001_initial.sql:ro
networks:
- netengine-integration
restart: on-failure
Expand Down
Loading
Loading