{"id":30615643,"url":"https://github.com/alexfalkowski/infraops","last_synced_at":"2026-05-24T05:04:57.676Z","repository":{"id":208310402,"uuid":"721320053","full_name":"alexfalkowski/infraops","owner":"alexfalkowski","description":"A place where all infrastructure is taken care of.","archived":false,"fork":false,"pushed_at":"2026-04-10T04:29:12.000Z","size":5004,"stargazers_count":2,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-04-10T06:28:38.731Z","etag":null,"topics":["cloudflare","digitalocean","github","golang","k8s"],"latest_commit_sha":null,"homepage":"https://alexfalkowski.github.io/infraops","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alexfalkowski.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2023-11-20T20:15:57.000Z","updated_at":"2026-04-10T04:29:17.000Z","dependencies_parsed_at":"2026-01-28T15:06:44.497Z","dependency_job_id":null,"html_url":"https://github.com/alexfalkowski/infraops","commit_stats":null,"previous_names":["alexfalkowski/infraops"],"tags_count":1233,"template":false,"template_full_name":null,"purl":"pkg:github/alexfalkowski/infraops","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexfalkowski%2Finfraops","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexfalkowski%2Finfraops/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexfalkowski%2Finfraops/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexfalkowski%2Finfraops/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alexfalkowski","download_url":"https://codeload.github.com/alexfalkowski/infraops/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexfalkowski%2Finfraops/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31876852,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-16T07:36:03.521Z","status":"ssl_error","status_checked_at":"2026-04-16T07:35:53.576Z","response_time":69,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cloudflare","digitalocean","github","golang","k8s"],"created_at":"2025-08-30T08:06:14.459Z","updated_at":"2026-05-24T05:04:57.670Z","avatar_url":"https://github.com/alexfalkowski.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Gopher](assets/gopher.png)\n[![DigitalOcean Referral Badge](https://web-platforms.sfo2.cdn.digitaloceanspaces.com/WWW/Badge%202.svg)](https://www.digitalocean.com/?refcode=b80d3d6467e1\u0026utm_campaign=Referral_Invite\u0026utm_medium=Referral_Program\u0026utm_source=badge)\n\n[![CircleCI](https://circleci.com/gh/alexfalkowski/infraops.svg?style=shield)](https://circleci.com/gh/alexfalkowski/infraops)\n[![codecov](https://codecov.io/gh/alexfalkowski/infraops/graph/badge.svg?token=U3X5JGAA8I)](https://codecov.io/gh/alexfalkowski/infraops)\n[![Go Report Card](https://goreportcard.com/badge/github.com/alexfalkowski/infraops/v2)](https://goreportcard.com/report/github.com/alexfalkowski/infraops/v2)\n[![Go Reference](https://pkg.go.dev/badge/github.com/alexfalkowski/infraops/v2.svg)](https://pkg.go.dev/github.com/alexfalkowski/infraops/v2)\n[![Stability: Active](https://masterminds.github.io/stability/active.svg)](https://masterminds.github.io/stability/active.html)\n\nA Go-based infrastructure “monorepo” powered by **Pulumi**, with configuration stored as **HJSON** and validated/decoded using a **protobuf schema**.\n\n## Overview\n\nThis repository manages multiple infrastructure “areas”:\n\n- `area/apps`: Kubernetes applications deployed to a cluster.\n- `area/cf`: Cloudflare resources (zones, DNS records, R2 buckets/custom domains).\n- `area/do`: DigitalOcean resources (VPC + Kubernetes clusters).\n- `area/gh`: GitHub repositories and settings (branch protection, Pages, collaborators).\n- `area/k8s`: Cluster add-ons installed via `helm`/`kubectl` (Makefile driven, not Pulumi).\n\nEach Pulumi area has:\n- a Pulumi entrypoint at `area/\u003cname\u003e/main.go`\n- a config file at `area/\u003cname\u003e/\u003cname\u003e.hjson`\n- a Pulumi project file `area/\u003cname\u003e/Pulumi.yaml`\n\nShared implementation lives under `internal/` (e.g. `internal/app`, `internal/cf`, `internal/do`, `internal/gh`).\n\n## Tooling\n\nPrimary tools used:\n\n- Pulumi: \u003chttps://www.pulumi.com/\u003e\n- kubectl: \u003chttps://kubernetes.io/docs/reference/kubectl/\u003e\n- Helm: \u003chttps://helm.sh/\u003e\n- kube-score: \u003chttps://kube-score.com/\u003e\n\n## Configuration (HJSON + protobuf schema)\n\nAll area configuration files are **HJSON** (`*.hjson`). They are decoded into protobuf messages defined in:\n\n- `api/infraops/v2/service.proto`\n\nThose protobuf messages are then converted into internal Go types and used to provision resources.\n\n### Format and normalize config\n\nThis repo includes a small CLI to normalize/format config files by:\n1) decoding the HJSON into the appropriate protobuf message\n2) writing it back out in a canonical form\n\nBuild:\n\n```bash\nmake build-format\n```\n\nFormat a config kind (`apps|cf|do|gh`), using the default location `area/\u003ckind\u003e/\u003ckind\u003e.hjson`:\n\n```bash\n./format -k cf\n```\n\nOverride the path:\n\n```bash\n./format -k cf -p area/cf/cf.hjson\n```\n\n### Config schema notes (practical)\n\nA few conventions are implemented by the Go code and are worth knowing when editing HJSON:\n\n#### `EnvVar.value` secret references (apps)\n\nEnvironment variables support literal values, and a secret reference format:\n\n- `secret:\u003csecretName\u003e/\u003ckey\u003e`\n\nAt deploy time, this becomes a Kubernetes `SecretKeyRef`:\n- Secret name: `\u003csecretName\u003e-secret`\n- Secret key: `\u003ckey\u003e`\n\nThe format is intentionally not pre-validated by the helper code; malformed references are expected\nto fail during Pulumi/Kubernetes application.\n\nExample:\n\n```hjson\nenv_vars: [\n  { name: \"DATABASE_URL\", value: \"secret:db/url\" }\n]\n```\n\n#### `Application.secrets` vs secret env vars (apps)\n\n- `Application.secrets` is an **application-level dependency list** used by the deployment implementation to provision and/or wire Secret resources (for example as volumes or attachments).\n- Secret references in `env_vars` (the `secret:\u003csecretName\u003e/\u003ckey\u003e` format) reference **specific keys** in those secrets.\n- They often use the same `\u003csecretName\u003e` values, but they serve different purposes.\n\n#### `Application.resource` sizing (apps)\n\n`Application.resource` selects a resource profile. Current mapping:\n\n- `\"small\"` (default): cpu `125m-250m`, memory `64Mi-128Mi`, ephemeral-storage `1Gi-2Gi`\n\nUnknown values fall back to `\"small\"`.\n\n#### App NetworkPolicy baseline\n\nThe apps Pulumi program creates a `NetworkPolicy` that selects each app's pods. Ingress is limited\nto the ports exposed by the app kind: external apps expose HTTP on `8080`, while internal apps expose\ndebug on `6060`, HTTP on `8080`, and gRPC on `9090`. Egress currently remains open because outbound\ntraffic flows are not modeled per app yet. Future egress restrictions should be introduced per\nnamespace/app after the required flows are known.\n\n## Common workflows\n\n### Dependencies, linting, tests, and security\n\nFrom the repository root:\n\n```bash\nmake dep          # download/tidy/vendor deps\nmake lint         # lint (including field alignment)\nmake sec          # govulncheck -test ./...\nmake specs        # gotestsum + go test (junit/coverage under test/reports)\nmake coverage     # HTML + function coverage under test/reports\n```\n\n### Protobuf / API\n\nDo not edit generated Go code under `api/infraops/v2/*.pb.go` directly.\n\nInstead:\n\n```bash\nmake api-lint\nmake api-breaking\nmake api-generate\n```\n\n(Or: `make -C api lint|breaking|generate`.)\n\n## Pulumi: preview/update per area\n\nPulumi is typically run via Makefile targets from the repo root.\n\nLogin:\n\n```bash\nmake pulumi-login\n```\n\nPreview/update:\n\n```bash\nmake area=cf pulumi-preview\nmake area=cf pulumi-update\n```\n\nSupported areas for these targets:\n\n- `apps`, `cf`, `do`, `gh`\n\nThe Makefile runs Pulumi with:\n- stack: `alexfalkowski/\u003carea\u003e/prod`\n- working directory: `area/\u003carea\u003e`\n\nThat working directory matters because the programs read `\u003carea\u003e.hjson` via a relative path.\n\n## Areas\n\n### Applications (`area/apps`)\n\nDeploys Kubernetes applications described in `area/apps/apps.hjson`.\n\n#### Configure\n\nSee:\n\n- `area/apps/apps.hjson`\n\nThis file uses the `Kubernetes` message in `api/infraops/v2/service.proto`.\n\n#### Install / Setup\n\nFor a full “apply” of what’s in config:\n\n```bash\nmake -C area/apps setup\n```\n\n#### Delete\n\n```bash\nmake -C area/apps delete\n```\n\n#### Update an application version (bump tool)\n\nBuild:\n\n```bash\nmake build-bump\n```\n\nUpdate a single app version in config. This is an internal helper used by automation, and the\n`-v` value is expected to be a semantic version:\n\n```bash\n./bump -n bezeichner -v 1.559.0\n```\n\nBy default it edits `area/apps/apps.hjson`. Override path:\n\n```bash\n./bump -n bezeichner -v 1.559.0 -p area/apps/apps.hjson\n```\n\n\u003e Tip: run `./format -k apps` after edits to keep config normalized.\n\n### Cloudflare (`area/cf`)\n\nManages Cloudflare resources using Pulumi’s Cloudflare provider:\n\n- \u003chttps://www.pulumi.com/registry/packages/cloudflare/\u003e\n\nConfig:\n\n- `area/cf/cf.hjson`\n\n#### Required environment variables\n\nThe implementation requires:\n\n- `CLOUDFLARE_ACCOUNT_ID`\n\n(Used for account-scoped resources like R2 buckets.)\n\n### DigitalOcean (`area/do`)\n\nManages DigitalOcean resources using Pulumi’s DigitalOcean provider:\n\n- \u003chttps://www.pulumi.com/registry/packages/digitalocean/\u003e\n\nConfig:\n\n- `area/do/do.hjson`\n\n#### Manual prerequisites (DigitalOcean UI)\n\nSome items may be created manually depending on account setup:\n\n- A default project (example):\n\n| Name          | Description                           |\n| ------------- | ------------------------------------- |\n| lean-thoughts | All of experiments for lean-thoughts. |\n\n- A default VPC in your target region (example):\n\n| Name         | Description               |\n| ------------ | ------------------------- |\n| default-fra1 | The default vpc for fra1. |\n\n#### Kubernetes cluster upgrades\n\nCluster version is pinned in code:\n\n- `internal/do/do.go`\n\nGuidance:\n- Patch versions can be updated in code.\n- Minor/major upgrades should be initiated via the DigitalOcean UI (per DO guidance), then aligned in code.\n\n### GitHub (`area/gh`)\n\nManages GitHub resources using Pulumi’s GitHub provider:\n\n- \u003chttps://www.pulumi.com/registry/packages/github/\u003e\n\nConfig:\n\n- `area/gh/gh.hjson`\n\nThis area was inspired by:\n\n- \u003chttps://github.com/dirien/pulumi-github\u003e\n\n#### Repository creation caveat (2-step enablement)\n\nSome repository features may require a two-step approach: create the repository first, then enable features in a follow-up change. This avoids timing issues around initial default branch creation.\n\n##### GitHub Pages\n\nFirst change: disable Pages (or omit pages config):\n\n```hjson\npages: { enabled: false }\n```\n\nSecond change: enable Pages:\n\n```hjson\npages: { enabled: true }\n```\n\nOptional CNAME:\n\n```hjson\npages: {\n  enabled: true\n  cname: www.yoursite.com\n}\n```\n\n##### Collaborators\n\nFirst change:\n\n```hjson\ncollaborators: { enabled: false }\n```\n\nSecond change:\n\n```hjson\ncollaborators: { enabled: true }\n```\n\nIf the pipeline fails due to timing, a rerun often succeeds.\n\n### Kubernetes add-ons (`area/k8s`)\n\nThis is not a Pulumi area. It contains cluster add-ons installed via `helm`/`kubectl`.\nThese targets are intended to be run manually from an operator workstation, not from CI.\n\n\u003e [!CAUTION]\n\u003e Run this only after you have a Kubernetes cluster (for example from `area/do`).\n\nSetup:\n\n```bash\nmake -C area/k8s setup\n```\n\nDelete:\n\n```bash\nmake -C area/k8s delete\n```\n\nUseful debugging:\n\n```bash\nmake -C area/k8s pods\n```\n\n#### Required environment variables (some add-ons)\n\nDepending on what you install, the k8s add-ons Makefile expects secrets like:\n\n- `CIRCLECI_K8S_TOKEN` (CircleCI release agent)\n- `BETTER_STACK_COLLECTOR_SECRET` (Better Stack collector)\n\nBecause the Makefile is a local-operator workflow, the CircleCI release-agent token is passed\ndirectly to Helm rather than through a CI secret-handling path.\n\n## Repository structure\n\n- `area/`: Pulumi programs and k8s add-ons\n- `internal/`: shared implementation (convert + create patterns per area)\n- `api/`: protobuf schema and generated code\n- `cmd/`: small helper CLIs (`format`, `bump`)\n- `bin/`: shared build tooling (git submodule)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falexfalkowski%2Finfraops","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falexfalkowski%2Finfraops","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falexfalkowski%2Finfraops/lists"}