# Tech Stack ## Overview | Layer | Technology | Version | Purpose | | --------------- | ---------- | ------- | ------- | | Policy language | Rego | OPA 1.x (`rego.v1`) | Authoring deployment-gateway policy rules and gates | | Policy engine | OPA | `v1.20.2` (pinned) | Evaluating, testing, type-checking and bundling the policies | | Policy linter | regal | `v0.42.0` | Static linting of Rego best practices (optional in CI) | | Bundles | OPA bundle format | — | Distributable `.tar.gz` bundles (rule modules at `data.rules.*`) | | Schemas | JSON Schema (draft 2020-12) | — | Static validation of `input` and `data` via `opa check --schema` | | Versioning | Changesets | `@changesets/cli@3.0.3` | Tracking per-policy version bumps across npm workspaces | | Changelog formatting | oxfmt | `^0.68.0` | Formatting generated changelogs/changesets via `format: "oxfmt"` | | Package management | npm workspaces | npm 11 / Node 24 | Monorepo layout (`policies/rules/*`, `policies/gates/*`) | | CI/CD | Gitea Actions | Gitea 1.27.0 | Verify, test, build and publish on `main` | | Package registry| Gitea generic registry | — | Storing published rule/gate bundles | | Build tooling | GNU make + bash | — | `Makefile` targets wrapping the scripts | | Hosting | Gitea self-hosted | `1.27.0` | Source control, CI runners, package registry (gitea.devegamoreno.com) | ## Justification - **OPA + Rego**: standard, policy-as-code engine for authorization/gating; bundles are the portable distribution unit; binary CLI avoids container runtime requirements. - **Pinned OPA `v1.20.2`**: reproducible engine version locally and in CI via `scripts/install-opa.sh` (no Docker), so tests and `opa build` see identical behaviour everywhere. - **`rego.v1`**: canonical OPA 1.x syntax (import of `rego.v1`), future-proof and unambiguous. - **Per-rule JSON Schemas**: `opa check --strict --schema` catches input/data type mistakes at authoring time instead of runtime. - **Separate evaluation / small rules**: each rule is an independent package+bundle with a small, testable contract; consumers combine the results at runtime, enabling reuse across gates. - **Changesets over npm workspaces**: each rule/gate is an npm package solely for versioning; changesets links repository-level changes to published registry versions. `oxfmt` is used only to format changelog markdown (there is no `prettier-plugin-rego` on npm), while Rego formatting is enforced by `opa fmt` in CI. - **Gitea generic registry**: stores arbitrary files (`.tar.gz` bundles) under `/api/packages/{owner}/generic/{package}/{version}/{file}` without adding an external registry dependency. - **npm workspaces** (over pnpm/yarn): zero extra tooling; changesets v3 requires Node ≥ 22.11 and npm ≥ 10.9, both met. ## Tools not used (and why) - **Docker/containers**: excluded by design; OPA ships a static binary, so containers add unnecessary runtime complexity for tests, checks and bundle builds. - **prettier-plugin-rego**: does not exist on npm (verified 404); Rego formatting is instead owned by `opa fmt`. - **pnpm/yarn**: changesets supports them, but npm workspaces suffice since these packages are private versioning shims, not published JS packages. ## Integration points - **Gitea Actions** reads `secrets.GITEA_TOKEN` (scope `write:package`) and `GITEA_OWNER`/`GITEA_URL`; publish job runs only on `main`. - **`scripts/publish.sh`** uploads via `curl` to the generic registry; package names are prefixed `rule-*` and `gate-*`. - **Consumer contract**: bundles scope roots to `rules` so operators can supply `data.deploygate.*` configuration separately and still have static schema checks apply. ## Environment (local dev machine) - macOS (darwin/arm64), zsh - Node.js `v24.18.0`, npm `11.16.0` - git `2.50.1`, GNU make - `tools/opa` (OPA `v1.20.2` binary committed to the repo working tree via install script, not git) - regal `v0.42.0` optional on `PATH`