Skip to content
This repository was archived by the owner on Sep 28, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/).

### Changed

- Recorded final Version 2 Greenfield clean-room acceptance as live-proven. A fresh OCI Cloud Shell and a fresh clone of `main` completed `tools/bootstrap-cloud-shell` → operator-local gitignored inputs → `tools/deploy-clean-room` (Terraform additive Greenfield apply, exact FORMAT gate for genuinely blank scratch, host / scratch / MicroK8s convergence). The first deploy stopped on the live-discovered Ubuntu 24.04 `python3-pip` / `python3-wheel` defect; after PR #75 merged, the same environment resumed from actual Terraform / Ansible / Kubernetes state. Resumed deploy completed: `private-runtime-config.yml` succeeded; Argo Applications reached Synced and Healthy after bounded WAIT states; Kubernetes workloads became healthy. `tools/verify-clean-room` then passed: Terraform no-drift, scratch mount, Argo / workloads, second `private-runtime-config.yml` and `site.yml` runs with `changed=0`, exact REBOOT gate, remote reboot with a changed boot ID, MicroK8s ready after reboot, scratch mount survived, and Argo / workloads returned healthy. Destroy acceptance then passed: pre-destroy Terraform no-drift, Terraform state contained only disposable root-owned infrastructure, the inspected saved destroy plan contained only delete actions for Terraform-owned disposable resources, external Vault / secret lifecycle / Object Storage state bucket were not in the plan, the reviewed plan applied, Terraform state was empty, and a fresh post-destroy plan was create/add-only (not applied). The external state bucket survived with Versioning Enabled and NoPublicAccess; the external Vault remained ACTIVE. Vault secret-value lifecycle is not Terraform-owned; secret contents were not re-read as a post-destroy proof. Resource count is taken from actual Terraform state for each run and is not a hard-coded destroy contract. Trailing “not yet live proven” phrases on the historical Fixed entries below describe the status when those Git corrections landed and are superseded by this acceptance.
- Made `docs/V2_CLEAN_ROOM_DEPLOYMENT.md` the canonical Greenfield V2 operator runbook for the existing clean-room tools, tracked Terraform provider lockfile, and destroy-acceptance procedure.
- Replaced a fixed repository-wide response-language rule with a task-driven contract in `AGENTS.md` and the always-applied foundation rule
- Documented the current GitHub `main-protection` required checks as present external policy, not future work
Expand Down
91 changes: 58 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Single-node infrastructure for quantitative research and backtesting on OCI.

| Generation | Role today | Path |
| --- | --- | --- |
| **Version 2** | **Current target** — Terraform → Ansible → Argo CD clean-room deploy | [`docs/V2_CLEAN_ROOM_DEPLOYMENT.md`](docs/V2_CLEAN_ROOM_DEPLOYMENT.md) |
| **Version 2** | **Current architecture** — Terraform → Ansible → Argo CD clean-room deploy | [`docs/V2_CLEAN_ROOM_DEPLOYMENT.md`](docs/V2_CLEAN_ROOM_DEPLOYMENT.md) |
| **Version 1** | Historical record — not an executable repository path | [`VERSION_1_BASELINE.md`](VERSION_1_BASELINE.md) |

V2 ownership:
Expand All @@ -27,8 +27,19 @@ That runbook is the canonical operator contract:
tools/bootstrap-cloud-shell → tools/deploy-clean-room → tools/verify-clean-room
```

GitHub Actions static validation is not live rebuild proof. Historical V1
executable paths are retired.
The canonical V2 clean-room path has been live-proven through:

```text
deploy → verify / idempotency → reboot → post-reboot convergence
→ destroy → empty Terraform state → fresh create/add-only plan
```

The external Object Storage state bucket and Vault foundation were preserved.
The path is resumable from actual Terraform / Ansible / Kubernetes state,
including after the live-discovered PR #75 system-pip fix. GitHub Actions
static validation is not live rebuild proof. Historical V1 executable paths
are retired. This is not a claim that Version 2 is multi-node, managed
Kubernetes, or production-grade.

The historical in-place SecretProviderClass handoff document
([`docs/RUNTIME_SPC_OWNERSHIP_CUTOVER.md`](docs/RUNTIME_SPC_OWNERSHIP_CUTOVER.md))
Expand All @@ -44,7 +55,7 @@ is a fallback procedure, not the primary V2 path.

## Architecture Overview

### Version 2 path (target)
### Version 2 path (current architecture)

See [`docs/V2_CLEAN_ROOM_DEPLOYMENT.md`](docs/V2_CLEAN_ROOM_DEPLOYMENT.md) for the
canonical operator sequence (`tools/bootstrap-cloud-shell` →
Expand Down Expand Up @@ -83,40 +94,44 @@ argocd/
│ ├── postgres/ # PostgreSQL deployment/pvc/service + DB init job
│ └── scratch/ # scratch PVC overlays for dev/prod
├── argocd/ # Argo CD Application definitions
├── VERSION_1_BASELINE.md # Version 1 ownership, limits, and V2 direction
├── VERSION_1_BASELINE.md # Historical Version 1 ownership and limits
├── CONTRIBUTING.md
├── SECURITY.md
└── README.md
```

## Prerequisites

- Ubuntu VM with sudo privileges
- `snap` available (used to install MicroK8s)
- Outbound network access from the VM to pull:
- snap packages
- Helm charts
- container images
- remote CRD/manifests (Prometheus Operator and Argo CD install URLs)
- OCI block device available at `/dev/oracleoci/oraclevds`
Canonical V2 deploy provisions the Ubuntu host with Terraform and configures
it with Ansible. Do not treat an already-prepared VM plus `.env` bootstrap as
the primary path. Operator procedure:
[`docs/V2_CLEAN_ROOM_DEPLOYMENT.md`](docs/V2_CLEAN_ROOM_DEPLOYMENT.md).

Platform requirements:

- Ubuntu host with `sudo` and `snap` (V2: Terraform-provisioned reference VM)
- Outbound network access from the VM to pull snap packages, Helm charts,
container images, and remote CRD/manifests
- Dedicated OCI scratch block volume (V2: Terraform-attached; Ansible
discovers the host device; kernel paths such as
`/dev/oracleoci/oraclevds` are not a stable contract)
- OCI Vault containing all required secret names (see [Required OCI Vault secrets](#required-oci-vault-secrets))
- OCI IAM configured so the instance principal can read those vault secrets

## Configuration

Copy and edit environment variables:
Version 2 operator inputs are gitignored files completed after
`tools/bootstrap-cloud-shell`:

```bash
cp .env.example .env
```text
terraform/backend.hcl
terraform/terraform.tfvars
ansible/extra-vars/private-runtime.yml
```

Load values into the current shell before bootstrap:

```bash
set -a
source .env
set +a
```
[`.env.example`](.env.example) remains a public reminder of Vault secret names
and of `VAULT_ID` / `OCI_REGION` as operator values. Ansible does not read
`.env`. Do not commit secret values or the gitignored input files.

### Environment variables

Expand All @@ -127,7 +142,7 @@ set +a

## Required OCI Vault Secrets

The following secret names are referenced directly by `SecretProviderClass` manifests and must exist in OCI Vault before bootstrap.
The following secret names must exist in OCI Vault before private-runtime materialization. Ansible renders them into SecretProviderClass resources; they are not stored as secret values in Git.

| Secret name | Used by | Purpose / expected value type | Source contract |
| --- | --- | --- | --- |
Expand All @@ -147,7 +162,10 @@ Do not commit secret values to Git.

All `SecretProviderClass` resources in this repository use `authType: instance`. The OCI provider DaemonSet also sets `OCI_RESOURCE_PRINCIPAL_VERSION`, indicating instance principal authentication.

This repository does not include OCI IAM policy text. You must configure OCI IAM policies so the instance principal can read the required vault secrets.
Version 2 Terraform owns the instance-principal Dynamic Group and the
compartment-scoped `read secret-bundles` policy for the reference compute
instance. Vault lifecycle, secret **values**, and any broader tenancy IAM
remain external.

## V1 historical record

Expand Down Expand Up @@ -256,7 +274,8 @@ Legacy V1 Bash storage bootstrap mounted `/mnt/scratch` while scratch PVCs used

## Post-Install Verification

Run these checks after bootstrap:
Canonical proof is `tools/verify-clean-room`. The commands below are host-side
debugging only and are not a substitute for that tool.

```bash
sudo microk8s status
Expand All @@ -269,8 +288,9 @@ sudo microk8s kubectl get pvc -A
What to verify:

- MicroK8s reports ready status
- Argo CD `Application` resources exist for all six apps listed above
- Pods are created in namespaces: `default`, `postgres`, `mlflow`, `monitoring`, `argo`, `dev`, `prod`
- Argo CD `Application` resources exist for the Applications listed above
- Pods are created in namespaces including `argocd`, `postgres`, `mlflow`,
`monitoring`, `argo`, `dev`, and `prod`
- Expected NodePorts are present (`30007`, `32120`, `30090`, `30500`)
- PVCs exist for `postgres-pvc` and `scratch-pvc` (dev/prod)

Expand Down Expand Up @@ -328,11 +348,16 @@ For vulnerability reporting and security policy, see `SECURITY.md`.

## Out of Scope / Limitations

- Multi-node Kubernetes production setups
- Managed Kubernetes providers
- Public service exposure configuration
Live Greenfield acceptance does not remove these architecture limits:

- Single-node MicroK8s (not a multi-node or highly available cluster)
- No managed Kubernetes provider
- Public service exposure configuration (cloud firewall / NSG remains external)
- Application business logic and trade execution systems
- Vault lifecycle and Vault secret **values** (referenced by Terraform / consumed via CSI; not provisioned as secret contents here)
- Vault lifecycle and Vault secret **values** (referenced by Terraform /
consumed via CSI; not provisioned as secret contents here)
- External Object Storage Terraform state-bucket lifecycle (operator-managed
foundation; not owned by this Terraform root)

Additional Version 1 limitations and evidence gaps are listed in [`VERSION_1_BASELINE.md`](VERSION_1_BASELINE.md).
The V2 clean-room operator procedure is [`docs/V2_CLEAN_ROOM_DEPLOYMENT.md`](docs/V2_CLEAN_ROOM_DEPLOYMENT.md).
Expand All @@ -347,7 +372,7 @@ This repository includes Cursor and agent guardrails for AI-assisted work. Start
- [`docs/REPOSITORY_SECURITY.md`](docs/REPOSITORY_SECURITY.md) — repository security CI and metadata hygiene
- [`docs/RUNTIME_SPC_OWNERSHIP_CUTOVER.md`](docs/RUNTIME_SPC_OWNERSHIP_CUTOVER.md) — historical in-place SPC handoff (fallback only)
- `terraform/README.md` / `ansible/README.md` / `argocd/README.md` — layer ownership
- `VERSION_1_BASELINE.md` for Version 1 ownership, limitations, and Version 2 direction
- `VERSION_1_BASELINE.md` for historical Version 1 ownership and limitations
- `AGENTS.md` for the cross-agent safety entry point
- [`docs/AI_AGENT_WORKFLOW.md`](docs/AI_AGENT_WORKFLOW.md) for the Cursor/AI-assisted implementation and review workflow
- `CONTRIBUTING.md` for contribution workflow
Expand Down
31 changes: 22 additions & 9 deletions VERSION_1_BASELINE.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
# Version 1 Baseline

This document describes the first-generation architecture of the repository (“Version 1”) as evidenced by the repository contents.
This document is the **historical** record of the first-generation architecture
(“Version 1”) as evidenced by the repository contents at that generation.

The project uses pre-1.0 semantic versioning while the infrastructure model is being stabilized. “Version 1” names the architecture generation; it is **not** the same as a SemVer tag such as `v1.0.0`. See `CHANGELOG.md` for published release history.
Version 2 is now the **active architecture**. The canonical operator path is
[`docs/V2_CLEAN_ROOM_DEPLOYMENT.md`](docs/V2_CLEAN_ROOM_DEPLOYMENT.md). This
file does not describe how to deploy Version 2 and is not an executable
Version 1 fallback.

The project uses pre-1.0 semantic versioning until an intentional release cut.
“Version 1” names the architecture generation; it is **not** the same as a
SemVer tag such as `v1.0.0`. See `CHANGELOG.md` for published release history.

It is documentation only. It does **not** claim that this architecture generation is production-ready, fully declarative, or fully automated.

Expand All @@ -23,10 +31,10 @@ Version 1 solves “bring up a usable single-node GitOps cluster on a prepared O

- Version 1 is a **single-node** platform baseline.
- It is **not** presented as a highly available or enterprise production platform.
- Version 2 (architecture direction) is expected to improve reproducibility and clear ownership without introducing unnecessary distributed-system complexity.
- Version 2 was the planned follow-on to improve reproducibility and clear ownership without introducing unnecessary distributed-system complexity. That generation is now the active architecture; see `docs/V2_CLEAN_ROOM_DEPLOYMENT.md`.
- SemVer release tags track repository releases; they do not by themselves redefine the architecture generation names used in this document.

## Current Ownership
## Version 1 Ownership

| Area | Version 1 owner |
| --- | --- |
Expand Down Expand Up @@ -117,23 +125,28 @@ These points are **not** confirmed as facts from the repository alone:
4. **Actual OCI NSG/Security List rules** — SECURITY and README describe an SSH-oriented access model; cloud firewall contents are not encoded in this repository.
5. **Terraform state backend and recovery targets** — not defined in Version 1; required before Version 2 OCI automation.

## Version 2 Direction
## Version 2 Direction (historical)

This section records the original Version 2 direction from the Version 1
baseline. Version 2 has since become the active architecture; the canonical
operator path is `docs/V2_CLEAN_ROOM_DEPLOYMENT.md`.

Version 1 achieves a usable single-node research cluster with GitOps-managed applications, but ownership is split across manual OCI setup, imperative Bash bootstrap, live Application patches, and Argo CD. That split limits reproducibility, idempotency, and auditability. Version 2 is needed to give each resource one clear owner and to move OCI and host lifecycle into reviewable automation.
Version 1 achieved a usable single-node research cluster with GitOps-managed applications, but ownership was split across manual OCI setup, imperative Bash bootstrap, live Application patches, and Argo CD. That split limited reproducibility, idempotency, and auditability. Version 2 was needed to give each resource one clear owner and to move OCI and host lifecycle into reviewable automation.

Planned ownership boundaries (direction only; not implemented by this baseline):
Ownership boundaries planned from this baseline (not implemented by Version 1):

- **Terraform** owns OCI infrastructure (network, compute, storage attachments, IAM references, Vault references as appropriate).
- **Ansible** owns host configuration, filesystems/mounts, MicroK8s, and the one-time Argo CD / root Application bootstrap.
- **Argo CD** owns long-lived Kubernetes platform and application resources.
- **GitHub Actions** validates Terraform, Ansible, shell, and Kubernetes configuration; it does not own runtime infrastructure.
- Every resource should have **one** clear owner.

Version 2 should preserve single-node clarity where appropriate and avoid unnecessary multi-node complexity unless requirements change.
Version 2 was intended to preserve single-node clarity where appropriate and avoid unnecessary multi-node complexity unless requirements change. That single-node limit remains in the active architecture.

## Related Documents

- `README.md` — operator guide and bootstrap usage
- `README.md` — current operator overview
- [`docs/V2_CLEAN_ROOM_DEPLOYMENT.md`](docs/V2_CLEAN_ROOM_DEPLOYMENT.md) — canonical Version 2 operator runbook
- `CHANGELOG.md` — change history and release tracking status
- `SECURITY.md` — vulnerability reporting and security policy
- `CONTRIBUTING.md` — contribution workflow
2 changes: 1 addition & 1 deletion ansible/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Ansible manages host configuration and bootstrap for the V2 reference platform.

## Ownership

Ansible owns or will own:
Ansible owns:

```text
host baseline
Expand Down
23 changes: 23 additions & 0 deletions docs/V2_CLEAN_ROOM_DEPLOYMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,29 @@ see [`RUNTIME_SPC_OWNERSHIP_CUTOVER.md`](RUNTIME_SPC_OWNERSHIP_CUTOVER.md).

---

## Live acceptance status

The documented Greenfield flow has been exercised end-to-end successfully
from a fresh OCI Cloud Shell and a fresh clone:

```text
deploy → verify / idempotency (changed=0) → reboot → post-reboot convergence
→ reviewed destroy → empty Terraform state → fresh create/add-only plan
```

The external Object Storage state bucket (Versioning Enabled, NoPublicAccess)
and the external Vault (ACTIVE) were preserved. The path is resumable from
actual Terraform / Ansible / Kubernetes state, including after the
live-discovered PR #75 system-pip fix. Vault secret **values** remain
operator-managed; their contents were not re-read as a post-destroy proof.

This status statement is not a substitute for the operator procedure below.
GitHub Actions static validation remains not live rebuild proof. Live
acceptance does not make Version 2 multi-node, managed Kubernetes, or
production-grade.

---

## Current operator contract vs historical context

### CURRENT OPERATOR CONTRACT
Expand Down
17 changes: 10 additions & 7 deletions terraform/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Terraform does **not** own:
- long-lived Kubernetes resources
- Vault lifecycle or secret values

Ansible will own host configuration and bootstrap.
Ansible owns host configuration and bootstrap.
Argo CD owns long-lived Kubernetes desired state.

## Network ownership
Expand Down Expand Up @@ -122,22 +122,25 @@ The reference instance can read secret bundles only in the configured secret com
It does not receive Vault, key, secret-management, or broad tenancy permissions.
```

V1 resolves secrets by name inside SecretProviderClass manifests. Secret OCIDs are not present in this repository, so compartment-scoped `read secret-bundles` is the minimal practical policy for this migration stage.
V1 resolved secrets by name inside SecretProviderClass manifests. Secret OCIDs are not present in this repository, so compartment-scoped `read secret-bundles` is the minimal practical policy for this architecture.
Further restriction to individual `target.secret.id` values remains a later hardening option once secret OCIDs are managed as explicit inputs.

### External Vault

```text
The Vault and secret values remain externally managed at this migration stage.
The Vault and secret values remain externally managed.
This Terraform root does not own Vault lifecycle or secret contents.
```

`oci_vault_id` is an infrastructure reference for later CSI / Argo CD configuration, not a secret value.
`oci_vault_id` is an infrastructure reference for CSI / private-runtime consumption, not a secret value.

### Later ownership
### Later hardening

```text
Terraform → OCI identity and access
Ansible/Argo CD later → CSI/provider/bootstrap and declarative Kubernetes secret consumption
Terraform → OCI identity and access (implemented in this root)
Argo CD → CSI Driver / OCI provider (`oci-secrets`) and workload secret consumption
Ansible → host bootstrap and private-runtime SecretProviderClass materialization
Further IAM restriction to individual target.secret.id values remains later
```

## Current managed scope
Expand Down
Loading