Compare commits

..

51 Commits

Author SHA1 Message Date
agent-company c5a8f9f58c [Phase 0] flux: add postBuild.substituteFrom for grafana-admin secret
Validate Flux manifests / kustomize-build (pull_request) Failing after 15s
Adds postBuild.substituteFrom to the Flux Kustomization reference manifest
so that ${GRAFANA_ADMIN_PASSWORD} in flux/monitoring/helmrelease.yaml is
substituted from the grafana-admin secret at reconcile time.

Without this block Flux passes the literal string to the Helm chart, causing
Grafana to start with a broken admin password.

The live copy in 0xWheatyz/Talos at
testing1/first-cluster/cluster/flux/api-company-source/kustomization.yaml
must also be updated with the same block (companion to issue #90).

Closes leeworks-agents/api-company#97
2026-05-29 15:02:13 +00:00
AI-Manager 8e64a9e2ac Merge pull request '[Phase 0] docs: add docs/tooling.md with tooling versions and git remote config' (#95) from feature/docs-tooling-md into main
Validate Flux manifests / kustomize-build (push) Failing after 21s
Build Docs Site / Aggregate OpenAPI Specs (push) Failing after 44s
2026-05-29 10:02:32 +00:00
agent-company 348baf96bb docs: add docs/tooling.md with Phase 0 tooling versions and git remote config
Validate Flux manifests / kustomize-build (pull_request) Failing after 22s
Documents Node.js v22.22.2, Python 3.11.2, Helm v3.21.0, Flux CLI v2.4.0,
kustomize v5.6.0 as available in the agent container. Confirms git remote
points to gitea.leeworks.dev/leeworks-agents/api-company. Includes stack
summary (runtime choices, Helm registry, Flux bootstrap reference) and
a live-verification block for operator use.

Closes leeworks-agents/api-company#94
2026-05-29 10:02:06 +00:00
AI-Manager cb9909172b Merge pull request '[Phase 3] fix(flux): move bedag HelmRepository to top-level to fix Flux race condition' (#93) from feature/fix-bedag-helmrepository-87 into main
Validate Flux manifests / kustomize-build (push) Failing after 8s
Build Docs Site / Aggregate OpenAPI Specs (push) Failing after 43s
2026-05-29 05:06:11 +00:00
AI-Manager 38cddd6dfc Merge pull request '[Phase 4] feat(monitoring): add APIDataCriticallyStale alert and fix APIDataStale for duration' (#92) from feature/add-data-freshness-alerts-88 into main
Build Docs Site / Aggregate OpenAPI Specs (push) Failing after 38s
Validate Flux manifests / kustomize-build (push) Failing after 18s
2026-05-29 05:06:00 +00:00
AI-Manager cd0ed86571 Merge pull request '[Phase 5] feat(docs-site): add legal pages (ToS, Privacy Policy, AUP)' (#91) from feature/add-legal-pages-89 into main
Validate Flux manifests / kustomize-build (push) Failing after 5s
Build Docs Site / Aggregate OpenAPI Specs (push) Failing after 43s
2026-05-29 05:05:55 +00:00
agent-company cb4c0649f5 feat(docs-site): add legal pages (ToS, Privacy Policy, AUP) and footer links
Validate Flux manifests / kustomize-build (pull_request) Failing after 20s
Add three Astro markdown pages under docs-site/src/pages/legal/:
- terms-of-service.md  -> /legal/terms-of-service
- privacy-policy.md    -> /legal/privacy-policy
- acceptable-use-policy.md -> /legal/acceptable-use-policy

All three use the Base.astro layout and render the legal content from
docs/legal/ (synced verbatim). The Base.astro layout already had legal
footer links added previously; this commit also adds a footer section
directly in index.astro for redundancy.

The ToS URL (https://docs.leeworks.dev/legal/terms-of-service) is now
ready to be pasted into the RapidAPI listing (issue #44).

Closes leeworks-agents/api-company#89
2026-05-29 05:05:13 +00:00
agent-company 1a1a109aa3 feat(monitoring): add APIDataCriticallyStale alert and fix APIDataStale for duration
Validate Flux manifests / kustomize-build (pull_request) Failing after 17s
- Fix APIDataStale 'for' duration from 5m to 30m (issue spec requires 30m)
- Add APIDataCriticallyStale alert at 60-day threshold (5184000s) with for: 1h
  and severity: critical

Both alerts fire on api_data_freshness_seconds metric for all three API jobs.
Existing APIHighErrorRate and APIHighLatency alerts are unmodified.
kustomize build flux/ passes.

Closes leeworks-agents/api-company#88
2026-05-29 05:04:56 +00:00
agent-company b616e11bdf fix(flux): move bedag HelmRepository to top-level to fix Flux race condition
Validate Flux manifests / kustomize-build (pull_request) Failing after 13s
The bedag HelmRepository was only declared inside flux/docs-site/, causing
a race condition where zip-enrichment, holidays, and air-quality HelmReleases
would fail with 'HelmRepository not found' if they reconciled before docs-site.

Move flux/docs-site/helmrepository.yaml -> flux/bedag-helmrepository.yaml and
add it as a top-level resource in flux/kustomization.yaml so it is always
available before any HelmRelease that depends on the bedag chart.

Closes leeworks-agents/api-company#87
2026-05-29 05:04:48 +00:00
AI-Manager 618d1acd68 Merge pull request '[Phase 5] Add Flux ImageRepository + ImagePolicy for docs-site image automation' (#86) from feature/issue-85-docs-site-image-automation into main
Build Docs Site / Aggregate OpenAPI Specs (push) Failing after 46s
Validate Flux manifests / kustomize-build (push) Failing after 17s
2026-05-29 00:02:55 +00:00
agent-company 459fc99f31 feat(flux): add docs-site ImageRepository, ImagePolicy, and setter marker
Validate Flux manifests / kustomize-build (pull_request) Failing after 51s
Closes leeworks-agents/api-company#85

- Add ImageRepository 'docs-site' in flux-system watching
  registry.leeworks.dev/leeworks-agents/docs-site (5m poll interval)
- Add ImagePolicy 'docs-site' in flux-system using alphabetical/asc
  ordering (consistent with SHA-tag CI pushes)
- Add $imagepolicy setter marker comment to flux/docs-site/helmrelease.yaml
  so Flux ImageUpdateAutomation can auto-commit new image tags

kustomize build flux/ = PASS
2026-05-29 00:02:23 +00:00
AI-Manager e470826a78 Merge pull request 'chore: update STATUS.md — 2026-05-28 cycle-2 triage' (#84) from feature/status-update-2026-05-28-cycle2 into main
Validate Flux manifests / kustomize-build (push) Failing after 21s
Build Docs Site / Aggregate OpenAPI Specs (push) Failing after 47s
2026-05-28 20:02:23 +00:00
agent-company c5947359c5 chore: update STATUS.md — 2026-05-28 cycle-2 triage
Validate Flux manifests / kustomize-build (pull_request) Failing after 26s
2026-05-28 20:02:12 +00:00
AI-Manager 5555c7524b Merge pull request 'chore: STATUS.md update — 2026-05-28 late-night triage' (#82) from feature/status-update-2026-05-28-night into main
Build Docs Site / Aggregate OpenAPI Specs (push) Failing after 43s
Validate Flux manifests / kustomize-build (push) Failing after 21s
2026-05-28 15:03:43 +00:00
agent-company 8c46feb1c6 chore: update STATUS.md for 2026-05-28 late-night triage cycle
Validate Flux manifests / kustomize-build (pull_request) Failing after 25s
Triaged issues #79, #80, #81 (all manual operator secret tasks).
No open PRs. kustomize build flux/ = PASS.
2026-05-28 15:03:20 +00:00
AI-Manager 28878773dd Merge pull request 'chore: update STATUS.md — 2026-05-28 night triage cycle' (#78) from feature/status-update-2026-05-28-night into main
Validate Flux manifests / kustomize-build (push) Failing after 16s
Build Docs Site / Aggregate OpenAPI Specs (push) Failing after 36s
2026-05-28 10:02:47 +00:00
agent-company c71651d4a2 chore: update STATUS.md — 2026-05-28 night triage cycle
Validate Flux manifests / kustomize-build (pull_request) Failing after 34s
Triaged issues #76 and #77 (new operator secret tasks for Flux GitRepository
auth and gitea-act-runner token). Both are blocked manual operator tasks;
instructions posted on each issue. No PRs open. kustomize build flux/ = PASS.
2026-05-28 10:02:30 +00:00
AI-Manager 636d68ced5 Merge pull request 'chore: update STATUS.md — 2026-05-28 evening triage cycle' (#75) from feature/status-update-2026-05-28-evening into main
Validate Flux manifests / kustomize-build (push) Failing after 21s
Build Docs Site / Aggregate OpenAPI Specs (push) Failing after 45s
2026-05-28 05:03:12 +00:00
agent-company b62bf046f6 chore: update STATUS.md — 2026-05-28 evening triage cycle
Validate Flux manifests / kustomize-build (pull_request) Failing after 21s
2026-05-28 05:02:57 +00:00
AI-Manager 181b9f9501 Merge pull request 'chore: update STATUS.md — 2026-05-28 morning triage cycle' (#72) from feature/status-update-2026-05-28-morning into main
Validate Flux manifests / kustomize-build (push) Failing after 24s
Build Docs Site / Aggregate OpenAPI Specs (push) Failing after 2m42s
2026-05-28 00:04:55 +00:00
agent-company d465c26832 chore: update STATUS.md — 2026-05-28 morning triage cycle
Validate Flux manifests / kustomize-build (pull_request) Failing after 21s
2026-05-28 00:04:41 +00:00
AI-Manager 49af1e73a6 Merge pull request 'ci: add Gitea Actions workflow to validate kustomize build on every PR (issue #69)' (#71) from feature/issue-69-gitea-actions-ci into main
Build Docs Site / Aggregate OpenAPI Specs (push) Failing after 48s
Validate Flux manifests / kustomize-build (push) Failing after 17s
2026-05-28 00:02:16 +00:00
agent-company d9a13d8c29 ci: add Gitea Actions workflow to validate kustomize build on every PR (Closes leeworks-agents/api-company#69)
Validate Flux manifests / kustomize-build (pull_request) Failing after 46s
2026-05-28 00:01:52 +00:00
AI-Manager 04102c75a4 Merge pull request 'chore: update STATUS.md — 2026-05-27 night triage cycle' (#68) from feature/status-update-2026-05-27-night into main
Build Docs Site / Aggregate OpenAPI Specs (push) Failing after 3m42s
2026-05-27 20:05:47 +00:00
agent-company 3860b44dc5 chore: update STATUS.md — 2026-05-27 night triage cycle
Triaged 2 new issues:
- #67: grafana.leeworks.dev DNS checklist — already covered in runbook (no code change)
- #66: Flux validation checklist — blocked on operator Phase 0 actions

kustomize build flux/ = PASS
2026-05-27 20:05:27 +00:00
AI-Manager 94631c18d0 Merge pull request 'feat: deploy External Secrets Operator (ESO) via Flux (issue #61)' (#65) from feature/issue-61-eso-flux into main
Build Docs Site / Aggregate OpenAPI Specs (push) Failing after 43s
2026-05-27 15:07:40 +00:00
AI-Manager c394c0c563 Merge pull request 'docs: add rapidapi-proxy-secret Step 10 to secrets-checklist (issue #60)' (#64) from feature/issue-60-rapidapi-proxy-secret-checklist into main
Build Docs Site / Aggregate OpenAPI Specs (push) Failing after 44s
Merge PR #64
2026-05-27 15:07:06 +00:00
AI-Manager 886d8e73d3 Merge pull request 'docs: add grafana.leeworks.dev as 7th DNS record (issue #62)' (#63) from feature/issue-62-dns-grafana into main
Build Docs Site / Aggregate OpenAPI Specs (push) Failing after 51s
2026-05-27 15:06:45 +00:00
agent-company 43f5d5ef60 feat: deploy External Secrets Operator (ESO) via Flux + real ExternalSecrets
Add flux/external-secrets/ directory containing:
- namespace.yaml: external-secrets namespace
- helmrepository.yaml: charts.external-secrets.io HelmRepository
- helmrelease.yaml: ESO HelmRelease (external-secrets/external-secrets >=0.9.0 <1.0.0)
- clustersecretstore.yaml: ClusterSecretStore using Kubernetes provider
  (ServiceAccount + ClusterRole + ClusterRoleBinding + ClusterSecretStore)
- kustomization.yaml: wires all above resources

Uncomment and complete ExternalSecret manifests in each API namespace:
- flux/zip-enrichment/externalsecret.yaml
- flux/holidays/externalsecret.yaml
- flux/air-quality/externalsecret.yaml

All three ExternalSecrets reference the kubernetes-provider ClusterSecretStore
and will auto-sync rapidapi-proxy-secret once ESO is running.

Add external-secrets to flux/kustomization.yaml.

kustomize build flux/ = PASS

Closes leeworks-agents/api-company#61
2026-05-27 15:05:54 +00:00
agent-company a0620ea391 docs: add Step 10 rapidapi-proxy-secret to secrets-checklist.md
Add checklist item 10 and full detail section for the rapidapi-proxy-secret
Kubernetes secret that must be created in each API namespace (zip-enrichment,
holidays, air-quality) before the Phase 3 server middleware can validate
incoming RapidAPI requests.

Includes:
- Checklist item 10 in the summary list
- Full detail section with kubectl commands for all 3 namespaces
- Note about placeholder ExternalSecret manifests and ESO (issue #61)
- Updated dependency-order diagram

Closes leeworks-agents/api-company#60
2026-05-27 15:04:45 +00:00
agent-company 8902feada7 docs: add grafana.leeworks.dev as 7th DNS record in dns.md and operator-runbook
- dns.md: fix '6 A records' wording to '7 A records'
- dns.md: add grafana.leeworks.dev to status checklist and dig verification block
- operator-runbook.md: fix 'all six' to 'all seven', add registry.leeworks.dev
  row to Phase 4 DNS table, add dig verification loop

Closes leeworks-agents/api-company#62
2026-05-27 15:04:13 +00:00
AI-Manager 13ce96e07e Merge pull request 'docs: add secrets-checklist items 8 & 9 (gitea-registry + gitea-image-automation-token)' (#59) from feature/secrets-checklist-items-8-9 into main
Build Docs Site / Aggregate OpenAPI Specs (push) Failing after 55s
2026-05-27 10:03:09 +00:00
agent-company fe9d867a87 docs: add secrets checklist items 8 and 9 for gitea-registry and gitea-image-automation-token
- Item 8: gitea-registry imagePullSecret in zip-enrichment, holidays,
  air-quality, docs-site namespaces (closes leeworks-agents/api-company#58)
- Item 9: gitea-image-automation-token in flux-system with write:repository
  scope for Flux ImageUpdateAutomation (closes leeworks-agents/api-company#57)
- Wire gitea-image-automation-token as push.secretRef in imageupdateautomation.yaml
- Update dependency order and item count from seven to nine
2026-05-27 10:02:42 +00:00
AI-Manager 9ad73f3741 Merge pull request 'chore: update STATUS.md — 2026-05-27 evening triage cycle' (#56) from feature/status-update-2026-05-27-evening into main
Build Docs Site / Aggregate OpenAPI Specs (push) Failing after 56s
2026-05-27 05:03:29 +00:00
agent-company e72a845c31 chore: update STATUS.md — 2026-05-27 evening triage cycle 2026-05-27 05:03:09 +00:00
AI-Manager b371c39c13 Merge pull request 'chore: update STATUS.md — 2026-05-27 ship cycle' (#55) from feature/status-update-2026-05-27-ship into main
Build Docs Site / Aggregate OpenAPI Specs (push) Failing after 54s
2026-05-27 00:42:22 +00:00
agent-company 33c6007899 chore: update STATUS.md — 2026-05-27 ship cycle 2026-05-27 00:41:58 +00:00
AI-Manager 9a1639ff4f Merge pull request 'chore: update STATUS.md — 2026-05-27 morning agent cycle' (#54) from feature/status-update-2026-05-27 into main
Build Docs Site / Aggregate OpenAPI Specs (push) Failing after 50s
2026-05-27 00:05:46 +00:00
agent-company 4ab65ca4dd chore: update STATUS.md — 2026-05-27 morning agent cycle 2026-05-27 00:05:28 +00:00
AI-Manager 7311df25bc Merge pull request 'chore: update STATUS.md — 2026-05-26 evening agent cycle' (#53) from feature/status-update-2026-05-26c into main
Build Docs Site / Aggregate OpenAPI Specs (push) Failing after 55s
2026-05-26 20:46:53 +00:00
agent-company 53466186b8 chore: update STATUS.md — 2026-05-26 evening agent cycle 2026-05-26 20:46:35 +00:00
AI-Manager 8d5ae5ee31 Merge pull request 'docs: add operator-runbook.md — ordered manual-action guide (closes #50)' (#52) from feature/operator-runbook-50 into main
Build Docs Site / Aggregate OpenAPI Specs (push) Failing after 57s
2026-05-26 20:46:01 +00:00
agent-company 82c9f70a01 feat: add Flux ImageRepository + ImagePolicy + ImageUpdateAutomation for all three API services (closes leeworks-agents/api-company#51) 2026-05-26 20:45:33 +00:00
agent-company 68a1524dca docs: add operator-runbook.md — ordered manual-action guide for operator (closes leeworks-agents/api-company#50) 2026-05-26 20:45:33 +00:00
AI-Manager bf19fb1cf5 Merge pull request 'chore: update STATUS.md — 2026-05-26 PM agent cycle' (#49) from feature/status-update-2026-05-26b into main
Build Docs Site / Aggregate OpenAPI Specs (push) Failing after 53s
2026-05-26 20:05:03 +00:00
agent-company 54cd793d5e chore: update STATUS.md — 2026-05-26 PM agent cycle 2026-05-26 20:04:40 +00:00
AI-Manager 58eba5f342 Merge pull request 'feat: scaffold Flux manifests for zip-enrichment, holidays, air-quality API services (closes #46)' (#48) from feature/flux-api-services-46 into main
Build Docs Site / Aggregate OpenAPI Specs (push) Failing after 49s
2026-05-26 20:03:47 +00:00
agent-company ae978a0bb3 feat: scaffold Flux manifests for zip-enrichment, holidays, air-quality API services
Closes leeworks-agents/api-company#46

Add flux/ directories for all three API services, each containing:
- namespace.yaml — Kubernetes Namespace
- helmrelease.yaml — HelmRelease using bedag/raw chart with Deployment,
  Service, and Ingress (TLS via cert-manager letsencrypt-prod)
- externalsecret.yaml — placeholder/comment for RapidAPI proxy-secret;
  includes kubectl manual-create instructions until ESO is deployed
- kustomization.yaml — per-directory Kustomize resources list

Services and subdomains:
  zip-enrichment  → zip.leeworks.dev
  holidays        → holidays.leeworks.dev
  air-quality     → aqi.leeworks.dev

Images:
  registry.leeworks.dev/zip-enrichment/server:latest
  registry.leeworks.dev/holidays/server:latest
  registry.leeworks.dev/air-quality/server:latest

Update root flux/kustomization.yaml to include all three new directories.
kustomize build flux/ passes with zero errors.
2026-05-26 20:02:42 +00:00
AI-Manager 01bfe2693a Merge pull request 'docs: add secrets-checklist.md — all required Kubernetes secrets with kubectl commands (closes #43)' (#45) from feature/secrets-checklist-43 into main
Build Docs Site / Aggregate OpenAPI Specs (push) Failing after 56s
2026-05-26 15:03:31 +00:00
agent-company 091c5cd089 docs: add secrets-checklist.md with kubectl commands for all required secrets
Closes leeworks-agents/api-company#43

Creates docs/secrets-checklist.md containing:
- Human operator checklist (7 checkboxes)
- Exact kubectl create secret commands for all required secrets
- Source of each secret value (Gitea admin UI, Slack, etc.)
- Which issues are unblocked by each secret
- Dependency order diagram

Secrets covered:
1. gitea-leeworks-agents-token (flux-system) → unblocks Flux GitRepo auth (#2)
2. gitea-runner-token (gitea-runner) → unblocks act-runner (#3)
3. grafana-admin (monitoring) → unblocks Grafana (#7)
4. gatus-slack-webhook (monitoring) → unblocks Gatus alerts (#8)
5. GITEA_TOKEN Actions secret (per repo) → unblocks CI image push
6. Gitea packages enable + DNS → unblocks registry (#4)
7. Flux source in Talos repo → unblocks GitOps (#2)
2026-05-26 15:03:05 +00:00
AI-Manager 997bf7bb12 Merge pull request 'chore: update STATUS.md — 2026-05-26 agent cycle' (#42) from feature/status-triage-2026-05-26 into main
Build Docs Site / Aggregate OpenAPI Specs (push) Failing after 51s
2026-05-26 10:08:16 +00:00
37 changed files with 1645 additions and 31 deletions
+21
View File
@@ -0,0 +1,21 @@
name: Validate Flux manifests
on:
pull_request:
branches: [main]
push:
branches: [main]
jobs:
kustomize-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install kustomize
run: |
curl -sL "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash
sudo mv kustomize /usr/local/bin/
- name: kustomize build flux/
run: kustomize build flux/ > /dev/null
+78 -25
View File
@@ -1,6 +1,6 @@
# Company Status
_Last updated: 2026-05-26 (agent cycle)_
_Last updated: 2026-05-28 (agent cycle — cycle-2 triage)_
## APIs
| API | Spec | Code | Deployed | Listed on RapidAPI | Paying Users | MRR |
@@ -18,8 +18,72 @@ Legend: [x]=done, [~]=in-progress, [ ]=not started
- **Container registry:** Gitea built-in registry selected; docs/registry.md committed — PENDING Gitea packages enabled (issue #4)
- **Prometheus + Grafana:** Flux HelmRelease at `flux/monitoring/` — PENDING Flux wiring + Grafana secret (issue #7)
- **Gatus status page:** Flux HelmRelease at `flux/monitoring/gatus-helmrelease.yaml` — PENDING Flux wiring (issue #8)
- **API service manifests:** `flux/zip-enrichment/`, `flux/holidays/`, `flux/air-quality/` scaffolded (PR #48, closes #46)
- **Image automation:** `flux/image-automation/` — ImageRepository + ImagePolicy + ImageUpdateAutomation for all three APIs
## Completed This Cycle (2026-05-26)
## Completed This Cycle (2026-05-28 — Cycle-2 Triage)
- **#83** — Triaged: `GITEA_TOKEN` Actions secrets needed in `zip-enrichment`, `holidays`, `air-quality` repos. Manual operator task; reuse token from #74 if it has `write:package` scope. Step-by-step instructions posted.
- **No open PRs** — queue empty.
- **`kustomize build flux/` = PASS** — no regressions.
- **Upstream `0xWheatyz/api-company`** — still does not exist; fork sync skipped (blocker #47).
## Completed Previous Cycle (2026-05-28 — Late-Night Triage)
- **#79** — Triaged: `gitea-registry` imagePullSecret needed in 4 namespaces. Manual operator task; kubectl docker-registry secret instructions posted.
- **#80** — Triaged: `gitea-image-automation-token` secret needed in `flux-system`. Manual operator task; write-scoped PAT required, kubectl instructions posted.
- **#81** — Triaged: `rapidapi-proxy-secret` needed in `zip-enrichment`, `holidays`, `air-quality`. Manual operator task; placeholder + real-secret commands posted.
- **No open PRs** — queue empty.
- **`kustomize build flux/` = PASS** — no regressions.
## Completed Previous Cycle (2026-05-28 — Night Triage)
- **#76** — Triaged: `gitea-leeworks-agents-token` secret required in `flux-system` to unblock Flux GitRepository auth. Manual operator task; kubectl instructions + reconcile steps posted in issue comment.
- **#77** — Triaged: `gitea-runner-token` secret required in `gitea-runner` namespace to register Act Runner. Manual operator task; full step-by-step instructions posted in issue comment.
- **No open PRs** — queue empty.
- **`kustomize build flux/` = PASS** — no regressions.
## Completed Previous Cycle (2026-05-28 — Evening Triage)
- **#74** — Triaged: `GITEA_TOKEN` Actions secret required in leeworks-agents/api-company for docs-site CI. Manual operator task; instructions posted.
- **#73** — Triaged: `gatus-slack-webhook` secret required in `monitoring` namespace. Manual operator task; kubectl instructions posted.
- **#67** — Confirmed already resolved: `docs/operator-runbook.md` and `docs/dns.md` both list all 7 subdomains incl. `grafana.leeworks.dev` (PR #63). No code change needed.
- **No open PRs** — queue empty.
- **`kustomize build flux/` = PASS** — no regressions.
## Completed Previous Cycle (2026-05-28 — Morning Triage)
- **#69 → PR #71 MERGED** — Added `.gitea/workflows/validate-flux.yaml` CI workflow: runs `kustomize build flux/` on every PR and push to `main`. CI gate enforced once Act Runner (#3) is online.
- **#70** — Triaged: `grafana-admin` secret needed in `monitoring` namespace. Manual operator task; kubectl instructions posted in issue comment.
- **#67** — Confirmed `docs/operator-runbook.md` Phase 4 DNS table already lists all 7 subdomains including grafana.leeworks.dev. No code change needed.
- **#66** — Blocked on Phase 0 operator actions (#47, #2, #3, #4). Status comment posted.
- **#47, #2, #3, #4, #7, #8, #16, #17, #18, #19, #27, #30, #33, #44** — Status comments posted confirming blocked/awaiting-operator state.
- **No open PRs to review** — queue empty after PR #71 merged.
- **`kustomize build flux/` = PASS** — no regressions.
## Completed Previous Cycle (2026-05-27 — Evening Triage)
- **Triage pass** — all 15 open agent-ready issues reviewed; status comments posted on each.
- **No open PRs** — nothing to merge or review.
- **No new feature work** — all issues remain blocked on operator actions or cross-repo prerequisites.
- **`kustomize build flux/` = PASS** — no regressions.
## Completed Previous Cycle (2026-05-27 — Ship/Afternoon)
- **PRs reviewed** — 0 open PRs on fork; nothing to merge.
- **Upstream sync** — `0xWheatyz/api-company` does not yet exist (blocker #41/#47); `git fetch upstream` failed as expected. Fork `origin/main` is current (SHA `9a1639f`).
- **`kustomize build flux/` = PASS** — all sub-trees validate cleanly; no regressions.
- **Deployment PR** — skipped; upstream repo must be created by operator first (#41, #47).
- **No new feature work** — all 15 open agent-ready issues remain blocked on operator actions.
## Completed Previous Cycle (2026-05-27 — Morning)
- **Triage pass** — all 15 open agent-ready issues reviewed; status comments posted/confirmed on each.
- **#19** — First triage comment posted: RapidAPI/PayPal operator task fully documented; all agent-side prerequisites (OpenAPI specs, listing copy, proxy-secret placeholders) confirmed ready.
- **No PRs to review** — fork had no open PRs.
- **No new feature work** — all open issues blocked on operator actions.
## Completed Previous Cycle (2026-05-26 Evening)
- **#50** — `docs/operator-runbook.md` added: ordered phase-by-phase manual for operator. PR #52 merged.
- **#51** — Flux image automation: `ImageRepository` + `ImagePolicy` + `ImageUpdateAutomation` for all three API services; setter markers added to HelmReleases. PR #52 merged. `kustomize build flux/ = PASS`.
## Completed Previous Cycle (2026-05-26 PM)
- **#46** — Scaffolded Flux deployment manifests for all three API services (zip-enrichment, holidays, air-quality). PR #48 merged.
## Completed Previous Cycle (2026-05-26 AM)
- **#43** — secrets-checklist.md added (closed, PR #45)
- **#36** — Cluster audit committed to `docs/cluster-audit.md` (closed)
- **#40** — Legal docs (ToS, Privacy Policy, AUP) under `docs/legal/` (closed)
- **#37** — docs-site Astro skeleton with Redoc pages; `npm run build` passes (closed)
@@ -28,33 +92,22 @@ Legend: [x]=done, [~]=in-progress, [ ]=not started
- **#34** — Cluster audit PR merged
## Flux Manifests (kustomize build flux/ = PASS)
All flux manifests validate successfully. Deployed components pending Flux activation:
All flux manifests validate successfully. Committed components pending Flux activation:
- `gitea-runner` namespace + HelmRelease (gitea-act-runner chart)
- `monitoring` namespace + kube-prometheus-stack HelmRelease
- `monitoring` Gatus HelmRelease (status.leeworks.dev, 90-day retention)
- `docs-site` HelmRelease (docs.leeworks.dev)
- `zip-enrichment` namespace + HelmRelease (zip.leeworks.dev) + rapidapi-proxy-secret placeholder
- `holidays` namespace + HelmRelease (holidays.leeworks.dev) + rapidapi-proxy-secret placeholder
- `air-quality` namespace + HelmRelease (aqi.leeworks.dev) + rapidapi-proxy-secret placeholder
- `image-automation` ImageRepository + ImagePolicy + ImageUpdateAutomation for all three APIs
## Blockers (human operator action required)
1. **Add api-company GitRepository+Kustomization to 0xWheatyz/Talos** at `testing1/first-cluster/cluster/flux/` — reference manifests ready in `flux/api-company-source/`
2. **Create `gitea-leeworks-agents-token` secret** in `flux-system` namespace (HTTPS token for Gitea)
3. **Create `gitea-runner-token` secret** in `gitea-runner` namespace (Gitea Admin → Actions → Runners → New Runner)
4. **Enable Gitea packages** (`[packages] ENABLED=true` in app.ini) + DNS record `registry.leeworks.dev` → Gitea ingress
5. **Create Grafana admin secret** in `monitoring` namespace (`GRAFANA_ADMIN_PASSWORD`)
6. **Create Slack webhook secret** in `monitoring` namespace for Gatus alerts
7. **DNS A records** for all 6 subdomains (zip, holidays, aqi, docs, status, registry) → cluster ingress IP (issue #33)
1. **Create `0xWheatyz/api-company` repo on Gitea** — every ship cycle fails until this exists (#41, #47) **<-- DO THIS FIRST**
2. **Add api-company GitRepository+Kustomization to 0xWheatyz/Talos** at `testing1/first-cluster/cluster/flux/` — reference manifests ready in `flux/api-company-source/` (#2)
3. **Create `gitea-leeworks-agents-token` secret** in `flux-system` namespace (HTTPS token for Gitea)
4. **Create `gitea-runner-token` secret** in `gitea-runner` namespace (Gitea Admin -> Actions -> Runners -> New Runner) (#3)
5. **Enable Gitea packages** (for container registry at `registry.leeworks.dev`) (#4)
6. **RapidAPI + PayPal setup** — manual, gated on operator turning 18 (#19, #44)
## API Repos Status
- `zip-enrichment`: Phase 3 server in progress (Fastify scaffold, routes, CI workflows)
- `holidays`: Phase 3 server in progress (Fastify scaffold, business-day routes)
- `air-quality`: Phase 1 in progress (openapi.yaml, Dockerfile)
## Revenue
- Gross MRR: $0
- Net MRR (after ~26.5% fees): $0
- Target: $100/mo net
- Gap: $100
## Next actions
1. **Human operator:** unblock infrastructure (items 1-7 above)
2. Once runner + Flux are live: API repo CI will build/push images and deploy to cluster
3. Phase 1→2→3 completion across zip-enrichment, holidays, air-quality repos
> Full ordered runbook with copy-paste commands: `docs/operator-runbook.md`
+10
View File
@@ -53,4 +53,14 @@ import Base from '../layouts/Base.astro';
</div>
</div>
</div>
<footer style="text-align: center; padding: 2rem; border-top: 1px solid #2d3748; margin-top: 3rem; color: #718096; font-size: 0.875rem;">
<p style="margin-bottom: 0.5rem;">&copy; 2026 leeworks.dev — All rights reserved.</p>
<nav style="display: flex; gap: 1.5rem; justify-content: center; flex-wrap: wrap;">
<a href="/legal/terms-of-service" style="color: #a0aec0; text-decoration: none;">Terms of Service</a>
<a href="/legal/privacy-policy" style="color: #a0aec0; text-decoration: none;">Privacy Policy</a>
<a href="/legal/acceptable-use-policy" style="color: #a0aec0; text-decoration: none;">Acceptable Use Policy</a>
<a href="mailto:legal@leeworks.dev" style="color: #a0aec0; text-decoration: none;">Contact</a>
</nav>
</footer>
</Base>
@@ -0,0 +1,67 @@
---
layout: ../../layouts/Base.astro
title: Acceptable Use Policy
description: leeworks.dev API Acceptable Use Policy
---
# Acceptable Use Policy
**Effective Date:** 2026-05-24
**Contact:** legal@leeworks.dev
---
## 1. Purpose
This Acceptable Use Policy ("AUP") defines the rules for using leeworks.dev APIs. It applies to all users regardless of plan. Violations may result in immediate account suspension.
## 2. Rate Limits and Abuse
### 2.1 Respect Your Plan Limits
Each subscription plan includes defined rate limits:
| Plan | Requests/min | Requests/month |
|------|-------------|---------------|
| Free | 10 | 500 |
| Basic | 60 | 10,000 |
| Pro | 300 | 100,000 |
| Ultra | 1,000 | 1,000,000 |
### 2.2 Prohibited Rate Limit Circumvention
The following are explicitly prohibited:
- Using multiple API keys or accounts to aggregate quota
- Caching responses for redistribution beyond your own application
- Rotating IP addresses or using proxies to bypass rate limits
## 3. Prohibited Uses
You may **not**:
- Download or cache the entire dataset backing any API
- Resell, sublicense, or redistribute API access to third parties
- Build a competing API product that serves our data to others
- Use the APIs for any illegal purpose
- Attempt to compromise the security or integrity of our systems
- Perform denial-of-service attacks against our infrastructure
- Probe our systems for vulnerabilities without prior written authorization
## 4. Acceptable Uses
The following are examples of acceptable use:
- Integrating ZIP code, holiday, or air quality data into your own product
- Building dashboards, mobile apps, or internal tools
- Academic research (within Free plan limits)
- Automated data fetching within your plan's rate limits
## 5. Enforcement
We continuously monitor API usage for abuse. Flagged accounts may be throttled, suspended, or permanently terminated for serious violations.
## 6. Reporting Abuse
Report misuse to **legal@leeworks.dev** immediately.
## 7. Contact
Questions about this policy: **legal@leeworks.dev**
@@ -0,0 +1,72 @@
---
layout: ../../layouts/Base.astro
title: Privacy Policy
description: leeworks.dev API Privacy Policy
---
# Privacy Policy
**Effective Date:** 2026-05-24
**Contact:** legal@leeworks.dev
---
## 1. Overview
leeworks.dev ("we", "us") operates the ZIP Enrichment, Holidays, and Air Quality APIs. This Privacy Policy describes what data we collect when you use our Services, how we use it, and your rights regarding that data.
## 2. What Data We Collect
### 2.1 Request Logs
When you make API calls, we log:
- API key identifier (hashed/truncated — not the full key)
- IP address of the requesting client
- HTTP method and endpoint path
- Response status code
- Request timestamp
- Response time (latency)
We do not log the full content of request or response bodies unless required for debugging.
### 2.2 Account Data (via RapidAPI)
If you subscribe through RapidAPI, your account data (name, email, billing information) is managed by RapidAPI, not by us. Please review RapidAPI's Privacy Policy at rapidapi.com/privacy.
### 2.3 Cookies and Tracking
The API endpoints themselves do not use cookies. Our documentation site (`docs.leeworks.dev`) may use minimal session cookies for navigation only — no analytics or tracking cookies.
## 3. How We Use Your Data
We use collected data to monitor API health, detect and prevent abuse, debug issues, generate aggregate usage statistics (anonymized), and respond to support requests.
**We do not sell your personal data to third parties. Ever.**
## 4. Data Retention
| Data Type | Retention Period |
|-----------|-----------------|
| Request logs (IP + endpoint) | 90 days |
| Aggregated usage metrics | 12 months |
| Billing records (via RapidAPI) | Per RapidAPI policy |
## 5. Data Sharing
We share data only with RapidAPI for billing and subscription management, when required by law, and with hosting infrastructure providers under data processing agreements.
## 6. Security
We take reasonable technical and organizational measures to protect your data including HTTPS-only API keys, restricted log access, and Kubernetes RBAC and network policies.
## 7. Your Rights
Depending on your jurisdiction, you may have rights to access, delete, or restrict processing of your personal data. Contact legal@leeworks.dev — we will respond within 30 days.
## 8. Changes to This Policy
We may update this Privacy Policy periodically. Continued use of the Services after changes constitutes acceptance.
## 9. Contact
For privacy inquiries: **legal@leeworks.dev**
@@ -0,0 +1,86 @@
---
layout: ../../layouts/Base.astro
title: Terms of Service
description: leeworks.dev API Terms of Service
---
# Terms of Service
**Effective Date:** 2026-05-24
**Contact:** legal@leeworks.dev
---
## 1. Acceptance of Terms
By accessing or using any API offered by leeworks.dev ("Services"), you agree to be bound by these Terms of Service. If you do not agree, do not use the Services.
## 2. Description of Services
leeworks.dev provides data API services including:
- ZIP Enrichment API (`zip.leeworks.dev`)
- Holidays API (`holidays.leeworks.dev`)
- Air Quality API (`aqi.leeworks.dev`)
These APIs are offered via RapidAPI and directly. Access requires a valid API key.
## 3. API Usage Limits
- Each plan has defined rate limits (requests per minute and per month). Exceeding your plan's limits will result in HTTP 429 responses.
- You must not circumvent rate limiting through multiple accounts, shared keys, or other technical means.
- Free and Basic plan users are limited to non-commercial use unless explicitly stated otherwise.
## 4. Prohibited Use
You may not use the Services to:
- Resell or redistribute the API data or API access without written permission
- Scrape, download, or replicate the underlying dataset in bulk
- Build a competing API product using our data
- Violate any applicable laws, including data privacy regulations
- Harass, harm, or interfere with other users or our infrastructure
See also the [Acceptable Use Policy](/legal/acceptable-use-policy).
## 5. Account Registration and Security
- You are responsible for keeping your API key confidential.
- You are responsible for all activity under your API key.
- Notify us immediately at legal@leeworks.dev if you suspect unauthorized use.
## 6. Payment and Billing
- Paid plans are billed through RapidAPI according to their billing terms.
- Refunds are handled at our discretion on a case-by-case basis. Contact legal@leeworks.dev within 7 days of a charge.
- We reserve the right to change pricing with 30 days' notice.
## 7. Data Accuracy Disclaimer
The data provided by leeworks.dev APIs is sourced from public datasets. We make no warranty as to the accuracy, completeness, or fitness for any particular purpose. You use the data at your own risk.
## 8. Service Availability
- We target 99.9% uptime but make no formal SLA guarantee on free or Basic plans.
- We reserve the right to take the service down for maintenance with or without notice.
- See status.leeworks.dev for real-time uptime information.
## 9. Intellectual Property
- The APIs, documentation, and underlying software are the intellectual property of leeworks.dev.
- Response data may be used in your own products subject to these Terms.
- You may not claim ownership of the data or present it as proprietary to you.
## 10. Termination
We may suspend or terminate your access to the Services immediately, without prior notice, for violation of these Terms, suspected abuse or fraud, or non-payment of applicable fees.
## 11. Limitation of Liability
TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, LEEWORKS.DEV SHALL NOT BE LIABLE FOR ANY INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, OR PUNITIVE DAMAGES, INCLUDING LOSS OF PROFITS, DATA, OR BUSINESS.
## 12. Changes to Terms
We may modify these Terms at any time. Continued use of the Services after changes constitutes acceptance.
## 13. Contact
Questions about these Terms? Contact us at: **legal@leeworks.dev**
+4 -2
View File
@@ -102,6 +102,7 @@ dig aqi.leeworks.dev +short
dig docs.leeworks.dev +short
dig status.leeworks.dev +short
dig registry.leeworks.dev +short
dig grafana.leeworks.dev +short
# Check TLS certificates (once services are deployed)
curl -v https://zip.leeworks.dev/health 2>&1 | grep -E "SSL|certificate|issuer"
@@ -125,7 +126,7 @@ The following actions require human operator access to the DNS provider:
1. Log into the DNS provider managing `leeworks.dev`
2. Find the cluster ingress IP: `kubectl get svc -n ingress-nginx ingress-nginx-controller`
3. Create/update the 6 A records listed in the table above
3. Create/update the 7 A records listed in the table above
4. Verify propagation: `dig +trace zip.leeworks.dev`
DNS propagation typically takes 560 minutes.
@@ -141,4 +142,5 @@ DNS propagation typically takes 560 minutes.
- [ ] `docs.leeworks.dev` → DNS record created
- [ ] `status.leeworks.dev` → DNS record created
- [ ] `registry.leeworks.dev` → DNS record created
- [ ] TLS certificates issued and valid for all 6 subdomains
- [ ] `grafana.leeworks.dev` → DNS record created
- [ ] TLS certificates issued and valid for all 7 subdomains
+309
View File
@@ -0,0 +1,309 @@
# Operator Runbook
**Audience:** Human operator (0xWheatyz)
**Purpose:** Ordered, copy-paste-ready guide to bring the full `api-company` stack live.
**Last updated:** 2026-05-26
**Closes:** leeworks-agents/api-company#50
---
## Overview
The agent has committed all Flux manifests and documentation. The only remaining
work is a set of manual steps that require Gitea admin access, `kubectl` access to
the `testing1` cluster, and external service accounts (RapidAPI, Slack, PayPal).
Work through these phases **in order** — each phase unblocks the next.
---
## Phase 0 — Create upstream repo (unblocks all ship cycles)
> **Why first?** Every agent deployment cycle fails to open a PR to upstream
> because `0xWheatyz/api-company` does not yet exist. This one step unblocks
> all automated deployments. See issues #41, #47.
### Step 0-A — Create `0xWheatyz/api-company` on Gitea
1. Log into Gitea as `0xWheatyz`.
2. **+** → **New Repository**.
3. Owner: `0xWheatyz`, Name: `api-company`.
4. Visibility: Public (or Private — your choice).
5. **Do not** initialise with a README.
6. Click **Create Repository**.
Once created, the agent's next ship cycle will open a deployment PR automatically.
---
## Phase 1 — Wire Flux to this repo (unblocks all GitOps reconciliation)
> **Why second?** Until Flux watches `leeworks-agents/api-company`, none of the
> manifests in `flux/` are applied to the cluster. See issue #2.
### Step 1-A — Create `gitea-leeworks-agents-token` secret in `flux-system`
```bash
# In Gitea: User Settings → Applications → Generate Token
# Scopes: read:repository (read-only is sufficient for Flux)
# Copy the token, then:
kubectl create secret generic gitea-leeworks-agents-token \
-n flux-system \
--from-literal=username=leeworks-agents \
--from-literal=password=<GITEA_TOKEN>
```
### Step 1-B — Copy Flux source + kustomization into 0xWheatyz/Talos
Reference manifests are at `flux/api-company-source/` in this repo.
Copy them verbatim to:
```
0xWheatyz/Talos:testing1/first-cluster/cluster/flux/api-company-source/
├── gitrepository.yaml
└── kustomization.yaml
```
You can do this via the Gitea web editor or locally:
```bash
cd /path/to/Talos-checkout
mkdir -p testing1/first-cluster/cluster/flux/api-company-source
# copy the two files from api-company/flux/api-company-source/
git add .
git commit -m "feat: wire Flux GitRepository + Kustomization for api-company"
git push origin main
```
**Verify reconciliation (after ~5 minutes):**
```bash
flux get sources git -n flux-system
flux get kustomizations -n flux-system
```
Both `api-company` entries should show `Ready = True`.
---
## Phase 2 — Secrets for already-staged services
Once Flux is watching the repo, it will attempt to reconcile all `flux/`
sub-directories. The HelmReleases will stall on missing secrets. Create them:
### Step 2-A — `gitea-runner-token` (unblocks Gitea Actions runner, issue #3)
```bash
# In Gitea: Admin Panel → Site Administration → Actions → Runners
# → Create new Runner → copy registration token
kubectl create secret generic gitea-runner-token \
-n gitea-runner \
--from-literal=token=<RUNNER_REGISTRATION_TOKEN>
```
**Verify:**
```bash
kubectl get pods -n gitea-runner
# Then check Gitea Admin → Actions → Runners — runner should appear Online
```
### Step 2-B — `grafana-admin` (unblocks Grafana, issue #7)
```bash
kubectl create secret generic grafana-admin \
-n monitoring \
--from-literal=admin-password=<CHOOSE_STRONG_PASSWORD>
```
Grafana URL: `https://grafana.leeworks.dev` (login: `admin` / `<PASSWORD>`)
### Step 2-C — `gatus-slack-webhook` (unblocks Gatus alerts, issue #8)
```bash
# Create an incoming webhook at: https://api.slack.com/messaging/webhooks
kubectl create secret generic gatus-slack-webhook \
-n monitoring \
--from-literal=url=https://hooks.slack.com/services/YOUR/WEBHOOK/URL
```
Gatus URL: `https://status.leeworks.dev`
### Step 2-D — Enable Gitea packages + registry DNS (issue #4)
**4a — Enable packages in Gitea `app.ini`:**
```ini
[packages]
ENABLED = true
```
Restart Gitea after editing `app.ini`.
**4b — Add DNS A record:**
```
registry.leeworks.dev → <cluster ingress IP>
```
Find the ingress IP:
```bash
kubectl get svc -n ingress-nginx
```
See `docs/registry.md` for additional context.
---
## Phase 3 — Enable CI image push (unblocks API service deployments)
Once the runner is online and the registry is reachable, CI pipelines can build
and push container images.
### Step 3-A — Add `GITEA_TOKEN` Actions Secret to each repo
Repos to configure:
- `leeworks-agents/api-company`
- `leeworks-agents/zip-enrichment`
- `leeworks-agents/holidays`
- `leeworks-agents/air-quality`
**For each repo:** Repo → Settings → Actions → Secrets → Add Secret
- **Name:** `GITEA_TOKEN`
- **Value:** Gitea personal access token with `write:packages` scope
### Step 3-B — Create image-automation token secret (issue #51)
The agent has added `ImageRepository` + `ImagePolicy` + `ImageUpdateAutomation`
manifests to `flux/image-automation/`. Flux will automatically update image tags
in HelmReleases when CI pushes new images — but it needs write access to commit
back:
```bash
kubectl create secret generic gitea-image-automation-token \
-n flux-system \
--from-literal=username=leeworks-agents \
--from-literal=password=<GITEA_TOKEN_WITH_WRITE_REPO>
```
---
## Phase 4 — DNS for API services (issue #33)
Add DNS A records for all seven leeworks.dev subdomains (all point to the same
cluster ingress IP):
| Hostname | Target |
|-------------------------|------------------------|
| `zip.leeworks.dev` | `<cluster ingress IP>` |
| `holidays.leeworks.dev` | `<cluster ingress IP>` |
| `aqi.leeworks.dev` | `<cluster ingress IP>` |
| `docs.leeworks.dev` | `<cluster ingress IP>` |
| `grafana.leeworks.dev` | `<cluster ingress IP>` |
| `status.leeworks.dev` | `<cluster ingress IP>` |
| `registry.leeworks.dev` | `<cluster ingress IP>` |
Verify DNS propagation:
```bash
for host in zip holidays aqi docs grafana status registry; do
echo -n "${host}.leeworks.dev: "
dig ${host}.leeworks.dev +short
done
```
cert-manager will obtain Let's Encrypt certificates automatically once DNS
propagates (typically minutes, up to 48 h).
---
## Phase 5 — RapidAPI + PayPal (issue #44, #19)
> **Blocked on operator being 18+ for PayPal.** Complete when eligible.
1. Create accounts on [rapidapi.com](https://rapidapi.com) and [paypal.com](https://www.paypal.com).
2. Link PayPal to RapidAPI as the payout method.
3. Submit each API to the RapidAPI marketplace using `docs/rapidapi-listings.md`.
4. Configure paid tiers per `ROADMAP.md`.
After submission, RapidAPI generates a `X-RapidAPI-Proxy-Secret` per API. Create:
```bash
# zip-enrichment
kubectl create secret generic rapidapi-proxy-secret \
-n zip-enrichment \
--from-literal=X-RapidAPI-Proxy-Secret=<VALUE>
# holidays
kubectl create secret generic rapidapi-proxy-secret \
-n holidays \
--from-literal=X-RapidAPI-Proxy-Secret=<VALUE>
# air-quality
kubectl create secret generic rapidapi-proxy-secret \
-n air-quality \
--from-literal=X-RapidAPI-Proxy-Secret=<VALUE>
```
---
## Quick Verification Checklist
```bash
# Flux overall health
flux get all -A
# API service pods
kubectl get pods -n zip-enrichment
kubectl get pods -n holidays
kubectl get pods -n air-quality
# Ingress + TLS
kubectl get ingress -A
kubectl get certificates -A
# Gitea runner
kubectl get pods -n gitea-runner
# Monitoring stack
kubectl get pods -n monitoring
# Image automation
flux get imagepolicies -A
flux get imagerepositories -A
```
---
## Dependency Summary
```
Phase 0: Create 0xWheatyz/api-company repo
└─► unblocks agent deployment PRs to upstream
Phase 1: Wire Flux (gitea-token secret + Talos manifests)
└─► all flux/ manifests reconcile
Phase 2: Service secrets (runner-token, grafana-admin, gatus-webhook, registry)
└─► runner online, monitoring live, registry reachable
Phase 3: CI secrets + image-automation token
└─► images build, push, and auto-update → API services deploy
Phase 4: DNS records
└─► HTTPS certs issued → public URLs go live
Phase 5: RapidAPI + PayPal
└─► revenue enabled
```
---
## Related Documents
| Document | Purpose |
|----------|---------|
| `docs/secrets-checklist.md` | Full checklist of all required secrets |
| `docs/registry.md` | Container registry architecture decision |
| `docs/cluster-audit.md` | Node/namespace/ingress inventory |
| `docs/rapidapi-listings.md` | RapidAPI marketplace submission details |
| `ROADMAP.md` | Full project roadmap and milestones |
| `STATUS.md` | Current cycle status and blockers |
+268
View File
@@ -0,0 +1,268 @@
# Kubernetes Secrets Checklist
All infrastructure blockers reduce to creating six Kubernetes secrets and one Gitea Actions secret.
Follow this list top-to-bottom; each step unblocks the next.
**Human operator only** — the agent cannot log into Gitea's admin panel or run `kubectl` in the cluster.
---
## Checklist
- [ ] 1. `gitea-leeworks-agents-token` (flux-system) — unblocks Flux GitRepository auth
- [ ] 2. `gitea-runner-token` (gitea-runner) — unblocks Gitea Actions runner registration
- [ ] 3. `grafana-admin` (monitoring) — unblocks Grafana login
- [ ] 4. `gatus-slack-webhook` (monitoring) — unblocks Gatus alert notifications
- [ ] 5. `GITEA_TOKEN` in each API repo's Actions Secrets — unblocks CI image push
- [ ] 6. Gitea packages enabled + DNS record for `registry.leeworks.dev` — unblocks image push to registry
- [ ] 7. Add api-company Flux source + kustomization to 0xWheatyz/Talos — unblocks all GitOps reconciliation
- [ ] 8. `gitea-registry` (zip-enrichment, holidays, air-quality, docs-site) — imagePullSecret for pods pulling from `registry.leeworks.dev`
- [ ] 9. `gitea-image-automation-token` (flux-system) — write-scoped token for Flux ImageUpdateAutomation to push image-tag commits
- [ ] 10. `rapidapi-proxy-secret` (zip-enrichment, holidays, air-quality) — RapidAPI Proxy Secret for server-side request validation
---
## Secret Details
### 1. `gitea-leeworks-agents-token`
| Field | Value |
|-----------|-------|
| Name | `gitea-leeworks-agents-token` |
| Namespace | `flux-system` |
| Purpose | Flux `GitRepository` authenticates to Gitea over HTTPS to pull `leeworks-agents/api-company` |
| Source | Gitea web UI → User Settings → Applications → Generate Token (scopes: `read:repository`) |
| Unblocks | Issue #2 (Flux GitRepository + Kustomization for api-company) |
```bash
kubectl create secret generic gitea-leeworks-agents-token \
-n flux-system \
--from-literal=username=leeworks-agents \
--from-literal=password=<GITEA_TOKEN>
```
---
### 2. `gitea-runner-token`
| Field | Value |
|-----------|-------|
| Name | `gitea-runner-token` |
| Namespace | `gitea-runner` |
| Purpose | The `gitea-act-runner` HelmRelease reads this token to register the runner with Gitea |
| Source | Gitea Admin Panel → Site Administration → Actions → Runners → **Create new Runner** — copy registration token |
| Unblocks | Issue #3 (gitea-act-runner Flux deployment) |
```bash
kubectl create secret generic gitea-runner-token \
-n gitea-runner \
--from-literal=token=<RUNNER_TOKEN>
```
After creating the secret, Flux reconciles the `gitea-act-runner` HelmRelease and the runner appears as **Online** in Gitea Admin → Actions → Runners.
---
### 3. `grafana-admin`
| Field | Value |
|-----------|-------|
| Name | `grafana-admin` |
| Namespace | `monitoring` |
| Purpose | Sets the Grafana `admin` user password on first boot |
| Source | Choose a strong password and store it in a password manager |
| Unblocks | Issue #7 (Prometheus + Grafana HelmRelease) |
```bash
kubectl create secret generic grafana-admin \
-n monitoring \
--from-literal=admin-password=<PASSWORD>
```
Grafana will be accessible at `https://grafana.leeworks.dev` (login: `admin` / `<PASSWORD>`).
---
### 4. `gatus-slack-webhook`
| Field | Value |
|-----------|-------|
| Name | `gatus-slack-webhook` |
| Namespace | `monitoring` |
| Purpose | Gatus posts downtime alerts to a Slack channel via incoming webhook |
| Source | Slack → Your workspace → Apps → Incoming Webhooks → Add to Slack → copy webhook URL |
| Unblocks | Issue #8 (Gatus status page at `status.leeworks.dev`) |
```bash
kubectl create secret generic gatus-slack-webhook \
-n monitoring \
--from-literal=url=https://hooks.slack.com/services/YOUR/WEBHOOK/URL
```
---
### 5. `GITEA_TOKEN` — Gitea Actions Secret (per repo)
| Field | Value |
|----------|-------|
| Name | `GITEA_TOKEN` |
| Scope | Gitea Actions Secret — set in each repo's Settings, **not** a Kubernetes secret |
| Purpose | CI workflows use this token to push container images to `registry.leeworks.dev` |
| Source | Same token as step 1, or a dedicated CI token with `write:packages` scope |
| Unblocks | CI pipelines for all three API repos |
Set in Gitea web UI for **each** of these repos:
- `leeworks-agents/api-company`
- `leeworks-agents/zip-enrichment`
- `leeworks-agents/holidays`
- `leeworks-agents/air-quality`
Path: **Repo → Settings → Actions → Secrets → Add Secret**
- Name: `GITEA_TOKEN`
- Value: `<GITEA_TOKEN>`
---
### 6. Enable Gitea Packages + DNS for `registry.leeworks.dev`
This is a Gitea instance configuration step, not a Kubernetes secret.
| Step | Action |
|------|--------|
| 6a | Enable packages in Gitea `app.ini`: set `[packages] ENABLED = true` then restart Gitea |
| 6b | Add DNS A record: `registry.leeworks.dev` → cluster ingress IP |
Find cluster ingress IP:
```bash
kubectl get svc -n ingress-nginx
```
See `docs/registry.md` for context on why the Gitea built-in registry was chosen.
Unblocks: Issue #4 (container registry), and transitively all CI image-push workflows.
---
### 7. Add api-company Flux Source + Kustomization to 0xWheatyz/Talos
Reference manifests are already committed at `flux/api-company-source/` in this repo.
The operator must copy them into the Talos cluster repo so FluxCD picks them up:
```
0xWheatyz/Talos:testing1/first-cluster/cluster/flux/api-company-source/
```
Unblocks: Issue #2 (Flux reconciliation of all `flux/` manifests in this repo).
---
---
### 10. `rapidapi-proxy-secret` — RapidAPI Proxy Secret (per API namespace)
| Field | Value |
|-----------|-------|
| Name | `rapidapi-proxy-secret` |
| Namespaces | `zip-enrichment`, `holidays`, `air-quality` |
| Purpose | Every API service validates the `X-RapidAPI-Proxy-Secret` header on every route. Requests without a valid secret return HTTP 403. |
| Source | RapidAPI dashboard → API Settings → Security → **Proxy Secret** (generated after each API listing is created) |
| Unblocks | Phase 3 server middleware; API services will start but reject all traffic without this secret |
```bash
for NS in zip-enrichment holidays air-quality; do
kubectl create secret generic rapidapi-proxy-secret \
--namespace=$NS \
--from-literal=X-RapidAPI-Proxy-Secret=<value-from-rapidapi-dashboard>
done
```
**Source:** RapidAPI dashboard → select your API → Settings → Security → Proxy Secret
> **Note:** Placeholder `ExternalSecret` manifests are committed at
> `flux/zip-enrichment/externalsecret.yaml`, `flux/holidays/externalsecret.yaml`,
> and `flux/air-quality/externalsecret.yaml`. These will auto-sync this secret
> from the configured backend once the External Secrets Operator (ESO) is
> deployed (see issue #61). Until then, create manually using the commands above.
Verify:
```bash
for NS in zip-enrichment holidays air-quality; do
echo -n "$NS: "
kubectl get secret rapidapi-proxy-secret -n $NS -o jsonpath='{.data.X-RapidAPI-Proxy-Secret}' | base64 -d | wc -c
echo " chars"
done
```
## Dependency Order
```
7 (Flux wiring) → all flux/ resources reconcile
1 (gitea-leeworks-token) → Flux can pull this repo over HTTPS
2 (gitea-runner-token) → runner online → CI runs
3 (grafana-admin) → Grafana login works
4 (gatus-slack-webhook) → Gatus alerting works
5 + 6 (GITEA_TOKEN + registry packages) → CI pushes images → API services deploy
8 (gitea-registry) → pods can pull images from registry.leeworks.dev → services start
9 (gitea-image-automation-token) → Flux ImageUpdateAutomation pushes tag-update commits
10 (rapidapi-proxy-secret × 3) → API server middleware validates RapidAPI requests → revenue enabled
```
Once all nine items are complete, the full stack (runner, registry, Prometheus, Grafana, Gatus, docs-site, three API services) reconciles automatically via FluxCD with no further manual steps.
---
### 8. `gitea-registry` — imagePullSecret for API service namespaces
| Field | Value |
|-----------|-------|
| Name | `gitea-registry` |
| Namespaces | `zip-enrichment`, `holidays`, `air-quality`, `docs-site` |
| Type | `kubernetes.io/dockerconfigjson` |
| Purpose | Allows pods to pull images from `registry.leeworks.dev` without ImagePullBackOff |
| Source | Gitea token with `read:packages` scope (can reuse the same token as step 1 if it has that scope) |
| Unblocks | Issues #58 (Phase 0 hard deploy blocker) and transitively Phase 3 service deploys |
```bash
for NS in zip-enrichment holidays air-quality docs-site; do
kubectl create secret docker-registry gitea-registry \
--namespace=$NS \
--docker-server=registry.leeworks.dev \
--docker-username=leeworks-agents \
--docker-password=<GITEA_TOKEN_WITH_READ_PACKAGES> \
--docker-email=agent@leeworks.dev
done
```
Verify:
```bash
kubectl get secret gitea-registry -n zip-enrichment -o jsonpath='{.type}'
# expected: kubernetes.io/dockerconfigjson
```
---
### 9. `gitea-image-automation-token` — Flux ImageUpdateAutomation write token
| Field | Value |
|-----------|-------|
| Name | `gitea-image-automation-token` |
| Namespace | `flux-system` |
| Purpose | Allows Flux `ImageUpdateAutomation` to push image-tag update commits back to `leeworks-agents/api-company` |
| Source | Gitea token with **`write:repository`** scope (the existing `gitea-leeworks-agents-token` only has `read:repository` — create a separate token or verify scope) |
| Unblocks | Issue #57 (Flux ImageUpdateAutomation for api-company) |
```bash
kubectl create secret generic gitea-image-automation-token \
-n flux-system \
--from-literal=username=leeworks-agents \
--from-literal=password=<TOKEN_WITH_WRITE_REPO_SCOPE>
```
Verify after creation:
```bash
flux get imageupdateautomations -n flux-system
# Expected: api-company shows READY=True
```
> **Note:** If you create a new token with `write:repository` scope, keep the existing `gitea-leeworks-agents-token` for read-only Flux GitRepository pulls and use this new secret exclusively for `ImageUpdateAutomation`.
+74
View File
@@ -0,0 +1,74 @@
# Tooling Versions
> Phase 0 checklist item — documents the local agent container tooling and confirms git remote config.
> Live cluster verification (kubectl/flux against the running cluster) requires operator confirmation.
## Agent Container Tooling
| Tool | Version | Source |
|------|---------|--------|
| Node.js | v22.22.2 | `node --version` |
| Python 3 | 3.11.2 | `python3 --version` |
| Helm | v3.21.0 | `helm version --short` |
| Flux CLI | v2.4.0 | `flux version --client` |
| kustomize | v5.6.0 | `kustomize version` |
| kubectl | available | `kubectl` (cluster context not set in agent container — live commands require kubeconfig from operator) |
## Git Remote Config
```
origin ssh://git@gitea.leeworks.dev/leeworks-agents/api-company (fetch)
origin ssh://git@gitea.leeworks.dev/leeworks-agents/api-company (push)
upstream ssh://git@gitea.leeworks.dev/0xWheatyz/api-company (fetch)
upstream ssh://git@gitea.leeworks.dev/0xWheatyz/api-company (push)
```
Remote `origin` confirmed pointing to `gitea.leeworks.dev/leeworks-agents/api-company`.
> Note: `0xWheatyz/api-company` upstream repo does not yet exist on Gitea — tracked by issue #47.
## Stack Summary
### Runtime choices
| API Service | Runtime | Rationale |
|-------------|---------|-----------|
| zip-enrichment | Node.js (Fastify) | Lightweight, fast JSON serialisation; large ZIP dataset fits SQLite well |
| holidays | Node.js (Fastify) | Simple lookup API; Fastify handles high req/s with low memory |
| air-quality | Python (FastAPI) | AQI ingestion benefits from Python data-science ecosystem |
| docs-site | Astro (static) | Zero-runtime static site; built by CI, served from container |
### Helm chart registry
All HelmReleases use charts sourced from public Helm chart repositories declared in `flux/` as `HelmRepository` resources:
- `flux/gitea-runner/helmrepository.yaml` — Gitea Act Runner chart
- `flux/monitoring/``kube-prometheus-stack` and Gatus charts
- `flux/zip-enrichment/`, `flux/holidays/`, `flux/air-quality/` — per-API service charts
The in-cluster container registry is `registry.leeworks.dev` (Gitea built-in packages/container registry, documented in `docs/registry.md`).
### Flux version and bootstrap
- **Flux CLI**: v2.4.0 (available in agent container for manifest authoring)
- **Flux controllers**: bootstrapped into `0xWheatyz/Talos` cluster (FluxCD v2.x)
- `flux-system` namespace managed by Talos GitOps repo
- Flux watches `0xWheatyz/Talos``testing1/first-cluster/cluster/`
- `api-company-source` GitRepository + Kustomization adds this repo to Flux (issues #2, #90)
- **Bootstrap reference**: `0xWheatyz/Talos` repo — see Talos cluster documentation
## Live Verification (Operator)
The following commands require a valid `kubeconfig` (not available in agent container):
```bash
kubectl config current-context # confirm cluster context
kubectl version --client # kubectl client version
flux check # Flux controller health
flux get sources git api-company # GitRepository READY status
flux get kustomizations api-company # Kustomization READY status
helm version # Helm client version
kustomize version # kustomize version
```
_Reference: MASTER_BUILD_PROMPT.md §Phase 0 step 2 — Closes leeworks-agents/api-company#94_
+18
View File
@@ -0,0 +1,18 @@
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: rapidapi-proxy-secret
namespace: air-quality
spec:
refreshInterval: 1h
secretStoreRef:
name: kubernetes-provider
kind: ClusterSecretStore
target:
name: rapidapi-proxy-secret
creationPolicy: Owner
data:
- secretKey: X-RapidAPI-Proxy-Secret
remoteRef:
key: rapidapi-air-quality-source
property: X-RapidAPI-Proxy-Secret
+101
View File
@@ -0,0 +1,101 @@
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: air-quality
namespace: air-quality
spec:
interval: 10m
chart:
spec:
chart: raw
version: ">=0.2.0"
sourceRef:
kind: HelmRepository
name: bedag
namespace: flux-system
interval: 60m
values:
resources:
- apiVersion: apps/v1
kind: Deployment
metadata:
name: air-quality
namespace: air-quality
spec:
replicas: 1
selector:
matchLabels:
app: air-quality
template:
metadata:
labels:
app: air-quality
spec:
imagePullSecrets:
- name: gitea-registry
containers:
- name: air-quality
image: registry.leeworks.dev/air-quality/server:latest # {"$imagepolicy": "flux-system:air-quality"}
ports:
- containerPort: 3000
env:
- name: RAPIDAPI_PROXY_SECRET
valueFrom:
secretKeyRef:
name: rapidapi-proxy-secret
key: X-RapidAPI-Proxy-Secret
resources:
requests:
cpu: 50m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 5
periodSeconds: 10
- apiVersion: v1
kind: Service
metadata:
name: air-quality
namespace: air-quality
spec:
selector:
app: air-quality
ports:
- port: 80
targetPort: 3000
- apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: air-quality
namespace: air-quality
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- aqi.leeworks.dev
secretName: air-quality-tls
rules:
- host: aqi.leeworks.dev
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: air-quality
port:
number: 80
+6
View File
@@ -0,0 +1,6 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- namespace.yaml
- externalsecret.yaml
- helmrelease.yaml
+4
View File
@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: air-quality
+7 -1
View File
@@ -1,7 +1,8 @@
# This manifest is FOR REFERENCE — the live version must be committed to
# 0xWheatyz/Talos at testing1/first-cluster/cluster/flux/api-company/
# 0xWheatyz/Talos at testing1/first-cluster/cluster/flux/api-company-source/
#
# See leeworks-agents/api-company#2
# See leeworks-agents/api-company#97
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
@@ -17,3 +18,8 @@ spec:
prune: true
wait: true
timeout: 5m
postBuild:
substituteFrom:
- kind: Secret
name: grafana-admin
optional: false
+1 -1
View File
@@ -35,7 +35,7 @@ spec:
- name: gitea-registry
containers:
- name: docs-site
image: registry.leeworks.dev/leeworks-agents/docs-site:latest
image: registry.leeworks.dev/leeworks-agents/docs-site:latest # {"$imagepolicy": "flux-system:docs-site"}
ports:
- containerPort: 80
resources:
-1
View File
@@ -2,5 +2,4 @@ apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- namespace.yaml
- helmrepository.yaml
- helmrelease.yaml
@@ -0,0 +1,50 @@
# ClusterSecretStore using the Kubernetes provider.
# Reads secrets from the cluster itself — no external vault required.
# The service account below must have get/list access to secrets in
# the namespaces where ExternalSecrets are created.
apiVersion: v1
kind: ServiceAccount
metadata:
name: eso-kubernetes-provider
namespace: external-secrets
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: eso-kubernetes-provider-reader
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: eso-kubernetes-provider-reader
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: eso-kubernetes-provider-reader
subjects:
- kind: ServiceAccount
name: eso-kubernetes-provider
namespace: external-secrets
---
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
name: kubernetes-provider
spec:
provider:
kubernetes:
remoteNamespace: external-secrets
server:
caProvider:
type: ConfigMap
name: kube-root-ca.crt
namespace: external-secrets
key: ca.crt
auth:
serviceAccount:
name: eso-kubernetes-provider
namespace: external-secrets
+30
View File
@@ -0,0 +1,30 @@
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: external-secrets
namespace: external-secrets
spec:
interval: 15m
chart:
spec:
chart: external-secrets
version: ">=0.9.0 <1.0.0"
sourceRef:
kind: HelmRepository
name: external-secrets
namespace: flux-system
interval: 60m
install:
crds: CreateReplace
remediation:
retries: 3
upgrade:
crds: CreateReplace
remediation:
retries: 3
values:
installCRDs: true
webhook:
port: 9443
certController:
requeueInterval: 5m
@@ -0,0 +1,8 @@
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: external-secrets
namespace: flux-system
spec:
interval: 60m
url: https://charts.external-secrets.io
+7
View File
@@ -0,0 +1,7 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- namespace.yaml
- helmrepository.yaml
- helmrelease.yaml
- clustersecretstore.yaml
+4
View File
@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: external-secrets
+18
View File
@@ -0,0 +1,18 @@
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: rapidapi-proxy-secret
namespace: holidays
spec:
refreshInterval: 1h
secretStoreRef:
name: kubernetes-provider
kind: ClusterSecretStore
target:
name: rapidapi-proxy-secret
creationPolicy: Owner
data:
- secretKey: X-RapidAPI-Proxy-Secret
remoteRef:
key: rapidapi-holidays-source
property: X-RapidAPI-Proxy-Secret
+101
View File
@@ -0,0 +1,101 @@
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: holidays
namespace: holidays
spec:
interval: 10m
chart:
spec:
chart: raw
version: ">=0.2.0"
sourceRef:
kind: HelmRepository
name: bedag
namespace: flux-system
interval: 60m
values:
resources:
- apiVersion: apps/v1
kind: Deployment
metadata:
name: holidays
namespace: holidays
spec:
replicas: 1
selector:
matchLabels:
app: holidays
template:
metadata:
labels:
app: holidays
spec:
imagePullSecrets:
- name: gitea-registry
containers:
- name: holidays
image: registry.leeworks.dev/holidays/server:latest # {"$imagepolicy": "flux-system:holidays"}
ports:
- containerPort: 3000
env:
- name: RAPIDAPI_PROXY_SECRET
valueFrom:
secretKeyRef:
name: rapidapi-proxy-secret
key: X-RapidAPI-Proxy-Secret
resources:
requests:
cpu: 50m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 5
periodSeconds: 10
- apiVersion: v1
kind: Service
metadata:
name: holidays
namespace: holidays
spec:
selector:
app: holidays
ports:
- port: 80
targetPort: 3000
- apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: holidays
namespace: holidays
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- holidays.leeworks.dev
secretName: holidays-tls
rules:
- host: holidays.leeworks.dev
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: holidays
port:
number: 80
+6
View File
@@ -0,0 +1,6 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- namespace.yaml
- externalsecret.yaml
- helmrelease.yaml
+4
View File
@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: holidays
+51
View File
@@ -0,0 +1,51 @@
# ImagePolicy: select the latest semver tag from each ImageRepository.
# Tags pushed by CI should follow semver (e.g. v1.2.3) or use "latest" —
# the semver policy picks up any vX.Y.Z tag. The "latest" alias keeps
# things working before formal releases are tagged.
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImagePolicy
metadata:
name: zip-enrichment
namespace: flux-system
spec:
imageRepositoryRef:
name: zip-enrichment
policy:
semver:
range: ">=0.1.0"
---
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImagePolicy
metadata:
name: holidays
namespace: flux-system
spec:
imageRepositoryRef:
name: holidays
policy:
semver:
range: ">=0.1.0"
---
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImagePolicy
metadata:
name: air-quality
namespace: flux-system
spec:
imageRepositoryRef:
name: air-quality
policy:
semver:
range: ">=0.1.0"
---
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImagePolicy
metadata:
name: docs-site
namespace: flux-system
spec:
imageRepositoryRef:
name: docs-site
policy:
alphabetical:
order: asc
@@ -0,0 +1,45 @@
# Flux image-reflector-controller watches these registries for new image tags.
# Requires: flux-system/gitea-image-automation-token secret (see docs/operator-runbook.md)
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageRepository
metadata:
name: zip-enrichment
namespace: flux-system
spec:
image: registry.leeworks.dev/zip-enrichment/server
interval: 5m
secretRef:
name: gitea-leeworks-agents-token
---
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageRepository
metadata:
name: holidays
namespace: flux-system
spec:
image: registry.leeworks.dev/holidays/server
interval: 5m
secretRef:
name: gitea-leeworks-agents-token
---
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageRepository
metadata:
name: air-quality
namespace: flux-system
spec:
image: registry.leeworks.dev/air-quality/server
interval: 5m
secretRef:
name: gitea-leeworks-agents-token
---
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageRepository
metadata:
name: docs-site
namespace: flux-system
spec:
image: registry.leeworks.dev/leeworks-agents/docs-site
interval: 5m
secretRef:
name: gitea-leeworks-agents-token
@@ -0,0 +1,39 @@
# ImageUpdateAutomation: when an ImagePolicy selects a new tag, this object
# instructs Flux to open a commit on the api-company repo updating the
# image reference in the relevant HelmRelease values.
#
# The GitRepository used here is the api-company source (flux-system/api-company).
# Flux needs write access; create the token secret first:
# kubectl create secret generic gitea-image-automation-token \
# -n flux-system \
# --from-literal=username=leeworks-agents \
# --from-literal=password=<TOKEN_WITH_WRITE_REPO>
# Then patch the api-company GitRepository to reference it (or reuse
# gitea-leeworks-agents-token if that token also has write:repository scope).
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageUpdateAutomation
metadata:
name: api-company
namespace: flux-system
spec:
interval: 10m
sourceRef:
kind: GitRepository
name: api-company
git:
checkout:
ref:
branch: main
commit:
author:
email: agent@leeworks.dev
name: Flux Image Automation
messageTemplate: |
chore(image): update {{range .Updated.Images}}{{.Repository}}:{{.NewTag}} {{end}}
push:
branch: main
secretRef:
name: gitea-image-automation-token # must pre-exist in flux-system ns — see docs/secrets-checklist.md item 9
update:
path: ./flux
strategy: Setters
+6
View File
@@ -0,0 +1,6 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- imagerepositories.yaml
- imagepolicies.yaml
- imageupdateautomation.yaml
+6
View File
@@ -1,6 +1,12 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- bedag-helmrepository.yaml
- external-secrets
- gitea-runner
- monitoring
- docs-site
- zip-enrichment
- holidays
- air-quality
- image-automation
+15 -1
View File
@@ -71,7 +71,7 @@ spec:
- alert: APIDataStale
expr: |
api_data_freshness_seconds{job=~"zip|holidays|air-quality"} > 2592000
for: 5m
for: 30m
labels:
severity: warning
team: api-company
@@ -79,6 +79,20 @@ spec:
summary: "Stale dataset on {{ $labels.job }} ({{ $labels.dataset }})"
description: "{{ $labels.job }} dataset '{{ $labels.dataset }}' has not been re-seeded in {{ $value | humanizeDuration }} (threshold: 30 days). Re-seed required."
# -------------------------------------------------------------------
# APIDataCriticallyStale — data freshness > 60 days
# -------------------------------------------------------------------
- alert: APIDataCriticallyStale
expr: |
api_data_freshness_seconds{job=~"zip|holidays|air-quality"} > 5184000
for: 1h
labels:
severity: critical
team: api-company
annotations:
summary: "API data is critically stale on {{ $labels.job }}"
description: "{{ $labels.job }} data has not been re-seeded in more than 60 days ({{ $value | humanizeDuration }})"
# -------------------------------------------------------------------
# APIDown — any API job absent for 2 min
# -------------------------------------------------------------------
+18
View File
@@ -0,0 +1,18 @@
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: rapidapi-proxy-secret
namespace: zip-enrichment
spec:
refreshInterval: 1h
secretStoreRef:
name: kubernetes-provider
kind: ClusterSecretStore
target:
name: rapidapi-proxy-secret
creationPolicy: Owner
data:
- secretKey: X-RapidAPI-Proxy-Secret
remoteRef:
key: rapidapi-zip-enrichment-source
property: X-RapidAPI-Proxy-Secret
+101
View File
@@ -0,0 +1,101 @@
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: zip-enrichment
namespace: zip-enrichment
spec:
interval: 10m
chart:
spec:
chart: raw
version: ">=0.2.0"
sourceRef:
kind: HelmRepository
name: bedag
namespace: flux-system
interval: 60m
values:
resources:
- apiVersion: apps/v1
kind: Deployment
metadata:
name: zip-enrichment
namespace: zip-enrichment
spec:
replicas: 1
selector:
matchLabels:
app: zip-enrichment
template:
metadata:
labels:
app: zip-enrichment
spec:
imagePullSecrets:
- name: gitea-registry
containers:
- name: zip-enrichment
image: registry.leeworks.dev/zip-enrichment/server:latest # {"$imagepolicy": "flux-system:zip-enrichment"}
ports:
- containerPort: 3000
env:
- name: RAPIDAPI_PROXY_SECRET
valueFrom:
secretKeyRef:
name: rapidapi-proxy-secret
key: X-RapidAPI-Proxy-Secret
resources:
requests:
cpu: 50m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 5
periodSeconds: 10
- apiVersion: v1
kind: Service
metadata:
name: zip-enrichment
namespace: zip-enrichment
spec:
selector:
app: zip-enrichment
ports:
- port: 80
targetPort: 3000
- apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: zip-enrichment
namespace: zip-enrichment
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- zip.leeworks.dev
secretName: zip-enrichment-tls
rules:
- host: zip.leeworks.dev
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: zip-enrichment
port:
number: 80
+6
View File
@@ -0,0 +1,6 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- namespace.yaml
- externalsecret.yaml
- helmrelease.yaml
+4
View File
@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: zip-enrichment