Payload
{
"action": "resolved",
"pull_request": {
"url": "https://api.github.com/repos/darkmatter/infra/pulls/21",
"id": 3792104481,
"node_id": "PR_kwDOPq3Cd87iBuwh",
"html_url": "https://github.com/darkmatter/infra/pull/21",
"diff_url": "https://github.com/darkmatter/infra/pull/21.diff",
"patch_url": "https://github.com/darkmatter/infra/pull/21.patch",
"issue_url": "https://api.github.com/repos/darkmatter/infra/issues/21",
"number": 21,
"state": "open",
"locked": false,
"title": "feat: autogenerate homepage dashboard config + gitops PR workflow",
"user": {
"login": "czxtm",
"id": 1325802,
"node_id": "MDQ6VXNlcjEzMjU4MDI=",
"avatar_url": "https://avatars.githubusercontent.com/u/1325802?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/czxtm",
"html_url": "https://github.com/czxtm",
"followers_url": "https://api.github.com/users/czxtm/followers",
"following_url": "https://api.github.com/users/czxtm/following{/other_user}",
"gists_url": "https://api.github.com/users/czxtm/gists{/gist_id}",
"starred_url": "https://api.github.com/users/czxtm/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/czxtm/subscriptions",
"organizations_url": "https://api.github.com/users/czxtm/orgs",
"repos_url": "https://api.github.com/users/czxtm/repos",
"events_url": "https://api.github.com/users/czxtm/events{/privacy}",
"received_events_url": "https://api.github.com/users/czxtm/received_events",
"type": "User",
"user_view_type": "public",
"site_admin": false
},
"body": "## What\n\nAutogenerates a [gethomepage/homepage](https://github.com/gethomepage/homepage) operator dashboard from the services in this repo **and** the k3s workloads in `darkmatter/gitops`, then ships it to the cluster.\n\nThe generator is a **third renderer** over the service single-source-of-truth — alongside `nix/apps/gatus.nix` (monitoring) and `nix/flake/apps/render-inventory-index.nix` (docs launcher). No parallel config to maintain.\n\n## Which layer\n\n`nix/` (flake app) + `.github/workflows/` (CI). The k8s manifests live in gitops — see the companion PR.\n\n## Changes\n\n| File | Change |\n|---|---|\n| `nix/flake/apps/render-homepage-config.nix` | **new** — generator (`writeShellApplication`) |\n| `nix/flake/apps.nix` | register `render-homepage-config` (x86_64-linux + aarch64-darwin) |\n| `config/service-catalog.nix` | additive optional `icon` field (+ one override); gatus/inventory consumers ignore it |\n| `.github/workflows/generate-homepage.yml` | **new** — regenerate + open PR on gitops via darkmatter-bot |\n| `docs/runbooks/homepage-dashboard.md` | **new** — operator runbook |\n\n## How it works\n\n`nix run .#render-homepage-config` reads:\n- `config/service-catalog.nix` (curated tiles) + `config/services.nix` (app deployments)\n- the gitops checkout: `apps/*.yaml` + `manifests/cloudflared/configmap.yaml` — the cloudflared ingress list is the **authoritative** hostname→Service map, so k3s tiles get clickable links dynamically (add a tunnel route → a card appears). The generator **self-excludes the `homepage` namespace** so the dashboard never lists itself.\n\n…and emits one `homepage` ConfigMap (services/settings/widgets/bookmarks.yaml). The workflow regenerates it on relevant pushes and opens a signed PR on `darkmatter/gitops`; ArgoCD deploys it at `home.darkmatter.io`.\n\n## Companion / prerequisites\n\n- **gitops bootstrap (deploys it):** darkmatter/gitops#16 — ArgoCD app + Deployment/Service/SA + first ConfigMap + cloudflared `home.darkmatter.io` route.\n- **One-time:** the `darkmatter-bot` App must be installed on `gitops` with Contents + Pull-requests write (it already powers `refresh-inventory.yml` on `infra`).\n- **Follow-up (not in scope):** DNS CNAME + Cloudflare Access SSO on `home.darkmatter.io` (homepage has no native auth).\n\n## Verification\n\n- `nix run .#render-homepage-config` → **31 services, 6 groups**; `kubeconform -strict` valid.\n- `actionlint` clean on the workflow.\n- App resolves on both `x86_64-linux` and `aarch64-darwin`.\n- Additive `icon` field confirmed non-breaking for gatus + inventory renderer.\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\n<!-- codesmith:footer -->\n---\n<a href=\"https://app.blacksmith.sh/darkmatter/codesmith/infra/pr/21\"><picture><source media=\"(prefers-color-scheme: dark)\" srcset=\"https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg\"><source media=\"(prefers-color-scheme: light)\" srcset=\"https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-light-v2.svg\"><img alt=\"View with Codesmith\" src=\"https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg\"></picture></a> <a href=\"https://backend.blacksmith.sh/track/enable-autofix?expires=1783041055&installation_id=137091173&pr_number=21&repository=darkmatter%2Finfra&return_to=https%3A%2F%2Fgithub.com%2Fdarkmatter%2Finfra%2Fpull%2F21&signature=c35b1e4c3bb01963ee543ab2b6a9d20a49782c22d39cf441667d2f6d9d42cc02\"><picture><source media=\"(prefers-color-scheme: dark)\" srcset=\"https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg\"><source media=\"(prefers-color-scheme: light)\" srcset=\"https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-light.svg\"><img alt=\"Autofix with Codesmith\" src=\"https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg\"></picture></a>\n<sup>Need help on this PR? Tag <code>@codesmith</code> with what you need. Autofix is disabled.</sup>\n\n<!-- codesmith:autofix:disabled -->\n<!-- /codesmith:footer -->",
"created_at": "2026-06-03T01:10:51Z",
"updated_at": "2026-06-03T15:05:08Z",
"closed_at": null,
"merged_at": null,
"merge_commit_sha": "57d48ce09bea2d9522f0eeab716d0f3a74a21d88",
"assignees": [],
"requested_reviewers": [
{
"login": "Copilot",
"id": 175728472,
"node_id": "BOT_kgDOCnlnWA",
"avatar_url": "https://avatars.githubusercontent.com/in/946600?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/Copilot",
"html_url": "https://github.com/apps/copilot-pull-request-reviewer",
"followers_url": "https://api.github.com/users/Copilot/followers",
"following_url": "https://api.github.com/users/Copilot/following{/other_user}",
"gists_url": "https://api.github.com/users/Copilot/gists{/gist_id}",
"starred_url": "https://api.github.com/users/Copilot/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/Copilot/subscriptions",
"organizations_url": "https://api.github.com/users/Copilot/orgs",
"repos_url": "https://api.github.com/users/Copilot/repos",
"events_url": "https://api.github.com/users/Copilot/events{/privacy}",
"received_events_url": "https://api.github.com/users/Copilot/received_events",
"type": "Bot",
"user_view_type": "public",
"site_admin": false
}
],
"requested_teams": [],
"labels": [],
"milestone": null,
"draft": false,
"commits_url": "https://api.github.com/repos/darkmatter/infra/pulls/21/commits",
"review_comments_url": "https://api.github.com/repos/darkmatter/infra/pulls/21/comments",
"review_comment_url": "https://api.github.com/repos/darkmatter/infra/pulls/comments{/number}",
"comments_url": "https://api.github.com/repos/darkmatter/infra/issues/21/comments",
"statuses_url": "https://api.github.com/repos/darkmatter/infra/statuses/0f54ce4ae5f865cd6426d3f515cdc0de65d32557",
"head": {
"label": "darkmatter:feat/homepage-config-generator",
"ref": "feat/homepage-config-generator",
"sha": "0f54ce4ae5f865cd6426d3f515cdc0de65d32557",
"user": {
"login": "darkmatter",
"id": 17834193,
"node_id": "MDEyOk9yZ2FuaXphdGlvbjE3ODM0MTkz",
"avatar_url": "https://avatars.githubusercontent.com/u/17834193?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/darkmatter",
"html_url": "https://github.com/darkmatter",
"followers_url": "https://api.github.com/users/darkmatter/followers",
"following_url": "https://api.github.com/users/darkmatter/following{/other_user}",
"gists_url": "https://api.github.com/users/darkmatter/gists{/gist_id}",
"starred_url": "https://api.github.com/users/darkmatter/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/darkmatter/subscriptions",
"organizations_url": "https://api.github.com/users/darkmatter/orgs",
"repos_url": "https://api.github.com/users/darkmatter/repos",
"events_url": "https://api.github.com/users/darkmatter/events{/privacy}",
"received_events_url": "https://api.github.com/users/darkmatter/received_events",
"type": "Organization",
"user_view_type": "public",
"site_admin": false
},
"repo": {
"id": 1051574903,
"node_id": "R_kgDOPq3Cdw",
"name": "infra",
"full_name": "darkmatter/infra",
"private": true,
"owner": {
"login": "darkmatter",
"id": 17834193,
"node_id": "MDEyOk9yZ2FuaXphdGlvbjE3ODM0MTkz",
"avatar_url": "https://avatars.githubusercontent.com/u/17834193?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/darkmatter",
"html_url": "https://github.com/darkmatter",
"followers_url": "https://api.github.com/users/darkmatter/followers",
"following_url": "https://api.github.com/users/darkmatter/following{/other_user}",
"gists_url": "https://api.github.com/users/darkmatter/gists{/gist_id}",
"starred_url": "https://api.github.com/users/darkmatter/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/darkmatter/subscriptions",
"organizations_url": "https://api.github.com/users/darkmatter/orgs",
"repos_url": "https://api.github.com/users/darkmatter/repos",
"events_url": "https://api.github.com/users/darkmatter/events{/privacy}",
"received_events_url": "https://api.github.com/users/darkmatter/received_events",
"type": "Organization",
"user_view_type": "public",
"site_admin": false
},
"html_url": "https://github.com/darkmatter/infra",
"description": "Versioned infra repo",
"fork": false,
"url": "https://api.github.com/repos/darkmatter/infra",
"forks_url": "https://api.github.com/repos/darkmatter/infra/forks",
"keys_url": "https://api.github.com/repos/darkmatter/infra/keys{/key_id}",
"collaborators_url": "https://api.github.com/repos/darkmatter/infra/collaborators{/collaborator}",
"teams_url": "https://api.github.com/repos/darkmatter/infra/teams",
"hooks_url": "https://api.github.com/repos/darkmatter/infra/hooks",
"issue_events_url": "https://api.github.com/repos/darkmatter/infra/issues/events{/number}",
"events_url": "https://api.github.com/repos/darkmatter/infra/events",
"assignees_url": "https://api.github.com/repos/darkmatter/infra/assignees{/user}",
"branches_url": "https://api.github.com/repos/darkmatter/infra/branches{/branch}",
"tags_url": "https://api.github.com/repos/darkmatter/infra/tags",
"blobs_url": "https://api.github.com/repos/darkmatter/infra/git/blobs{/sha}",
"git_tags_url": "https://api.github.com/repos/darkmatter/infra/git/tags{/sha}",
"git_refs_url": "https://api.github.com/repos/darkmatter/infra/git/refs{/sha}",
"trees_url": "https://api.github.com/repos/darkmatter/infra/git/trees{/sha}",
"statuses_url": "https://api.github.com/repos/darkmatter/infra/statuses/{sha}",
"languages_url": "https://api.github.com/repos/darkmatter/infra/languages",
"stargazers_url": "https://api.github.com/repos/darkmatter/infra/stargazers",
"contributors_url": "https://api.github.com/repos/darkmatter/infra/contributors",
"subscribers_url": "https://api.github.com/repos/darkmatter/infra/subscribers",
"subscription_url": "https://api.github.com/repos/darkmatter/infra/subscription",
"commits_url": "https://api.github.com/repos/darkmatter/infra/commits{/sha}",
"git_commits_url": "https://api.github.com/repos/darkmatter/infra/git/commits{/sha}",
"comments_url": "https://api.github.com/repos/darkmatter/infra/comments{/number}",
"issue_comment_url": "https://api.github.com/repos/darkmatter/infra/issues/comments{/number}",
"contents_url": "https://api.github.com/repos/darkmatter/infra/contents/{+path}",
"compare_url": "https://api.github.com/repos/darkmatter/infra/compare/{base}...{head}",
"merges_url": "https://api.github.com/repos/darkmatter/infra/merges",
"archive_url": "https://api.github.com/repos/darkmatter/infra/{archive_format}{/ref}",
"downloads_url": "https://api.github.com/repos/darkmatter/infra/downloads",
"issues_url": "https://api.github.com/repos/darkmatter/infra/issues{/number}",
"pulls_url": "https://api.github.com/repos/darkmatter/infra/pulls{/number}",
"milestones_url": "https://api.github.com/repos/darkmatter/infra/milestones{/number}",
"notifications_url": "https://api.github.com/repos/darkmatter/infra/notifications{?since,all,participating}",
"labels_url": "https://api.github.com/repos/darkmatter/infra/labels{/name}",
"releases_url": "https://api.github.com/repos/darkmatter/infra/releases{/id}",
"deployments_url": "https://api.github.com/repos/darkmatter/infra/deployments",
"created_at": "2025-09-06T09:28:59Z",
"updated_at": "2026-06-03T14:06:12Z",
"pushed_at": "2026-06-03T15:05:06Z",
"git_url": "git://github.com/darkmatter/infra.git",
"ssh_url": "git@github.com:darkmatter/infra.git",
"clone_url": "https://github.com/darkmatter/infra.git",
"svn_url": "https://github.com/darkmatter/infra",
"homepage": null,
"size": 59144,
"stargazers_count": 0,
"watchers_count": 0,
"language": "Nix",
"has_issues": true,
"has_projects": true,
"has_downloads": true,
"has_wiki": true,
"has_pages": true,
"has_discussions": false,
"forks_count": 0,
"mirror_url": null,
"archived": false,
"disabled": false,
"open_issues_count": 2,
"license": null,
"allow_forking": false,
"is_template": false,
"web_commit_signoff_required": false,
"has_pull_requests": true,
"pull_request_creation_policy": "all",
"topics": [],
"visibility": "private",
"forks": 0,
"open_issues": 2,
"watchers": 0,
"default_branch": "main"
}
},
"base": {
"label": "darkmatter:main",
"ref": "main",
"sha": "2e2e378416e4cd8a586e676ffe611bf60ec7dfae",
"user": {
"login": "darkmatter",
"id": 17834193,
"node_id": "MDEyOk9yZ2FuaXphdGlvbjE3ODM0MTkz",
"avatar_url": "https://avatars.githubusercontent.com/u/17834193?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/darkmatter",
"html_url": "https://github.com/darkmatter",
"followers_url": "https://api.github.com/users/darkmatter/followers",
"following_url": "https://api.github.com/users/darkmatter/following{/other_user}",
"gists_url": "https://api.github.com/users/darkmatter/gists{/gist_id}",
"starred_url": "https://api.github.com/users/darkmatter/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/darkmatter/subscriptions",
"organizations_url": "https://api.github.com/users/darkmatter/orgs",
"repos_url": "https://api.github.com/users/darkmatter/repos",
"events_url": "https://api.github.com/users/darkmatter/events{/privacy}",
"received_events_url": "https://api.github.com/users/darkmatter/received_events",
"type": "Organization",
"user_view_type": "public",
"site_admin": false
},
"repo": {
"id": 1051574903,
"node_id": "R_kgDOPq3Cdw",
"name": "infra",
"full_name": "darkmatter/infra",
"private": true,
"owner": {
"login": "darkmatter",
"id": 17834193,
"node_id": "MDEyOk9yZ2FuaXphdGlvbjE3ODM0MTkz",
"avatar_url": "https://avatars.githubusercontent.com/u/17834193?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/darkmatter",
"html_url": "https://github.com/darkmatter",
"followers_url": "https://api.github.com/users/darkmatter/followers",
"following_url": "https://api.github.com/users/darkmatter/following{/other_user}",
"gists_url": "https://api.github.com/users/darkmatter/gists{/gist_id}",
"starred_url": "https://api.github.com/users/darkmatter/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/darkmatter/subscriptions",
"organizations_url": "https://api.github.com/users/darkmatter/orgs",
"repos_url": "https://api.github.com/users/darkmatter/repos",
"events_url": "https://api.github.com/users/darkmatter/events{/privacy}",
"received_events_url": "https://api.github.com/users/darkmatter/received_events",
"type": "Organization",
"user_view_type": "public",
"site_admin": false
},
"html_url": "https://github.com/darkmatter/infra",
"description": "Versioned infra repo",
"fork": false,
"url": "https://api.github.com/repos/darkmatter/infra",
"forks_url": "https://api.github.com/repos/darkmatter/infra/forks",
"keys_url": "https://api.github.com/repos/darkmatter/infra/keys{/key_id}",
"collaborators_url": "https://api.github.com/repos/darkmatter/infra/collaborators{/collaborator}",
"teams_url": "https://api.github.com/repos/darkmatter/infra/teams",
"hooks_url": "https://api.github.com/repos/darkmatter/infra/hooks",
"issue_events_url": "https://api.github.com/repos/darkmatter/infra/issues/events{/number}",
"events_url": "https://api.github.com/repos/darkmatter/infra/events",
"assignees_url": "https://api.github.com/repos/darkmatter/infra/assignees{/user}",
"branches_url": "https://api.github.com/repos/darkmatter/infra/branches{/branch}",
"tags_url": "https://api.github.com/repos/darkmatter/infra/tags",
"blobs_url": "https://api.github.com/repos/darkmatter/infra/git/blobs{/sha}",
"git_tags_url": "https://api.github.com/repos/darkmatter/infra/git/tags{/sha}",
"git_refs_url": "https://api.github.com/repos/darkmatter/infra/git/refs{/sha}",
"trees_url": "https://api.github.com/repos/darkmatter/infra/git/trees{/sha}",
"statuses_url": "https://api.github.com/repos/darkmatter/infra/statuses/{sha}",
"languages_url": "https://api.github.com/repos/darkmatter/infra/languages",
"stargazers_url": "https://api.github.com/repos/darkmatter/infra/stargazers",
"contributors_url": "https://api.github.com/repos/darkmatter/infra/contributors",
"subscribers_url": "https://api.github.com/repos/darkmatter/infra/subscribers",
"subscription_url": "https://api.github.com/repos/darkmatter/infra/subscription",
"commits_url": "https://api.github.com/repos/darkmatter/infra/commits{/sha}",
"git_commits_url": "https://api.github.com/repos/darkmatter/infra/git/commits{/sha}",
"comments_url": "https://api.github.com/repos/darkmatter/infra/comments{/number}",
"issue_comment_url": "https://api.github.com/repos/darkmatter/infra/issues/comments{/number}",
"contents_url": "https://api.github.com/repos/darkmatter/infra/contents/{+path}",
"compare_url": "https://api.github.com/repos/darkmatter/infra/compare/{base}...{head}",
"merges_url": "https://api.github.com/repos/darkmatter/infra/merges",
"archive_url": "https://api.github.com/repos/darkmatter/infra/{archive_format}{/ref}",
"downloads_url": "https://api.github.com/repos/darkmatter/infra/downloads",
"issues_url": "https://api.github.com/repos/darkmatter/infra/issues{/number}",
"pulls_url": "https://api.github.com/repos/darkmatter/infra/pulls{/number}",
"milestones_url": "https://api.github.com/repos/darkmatter/infra/milestones{/number}",
"notifications_url": "https://api.github.com/repos/darkmatter/infra/notifications{?since,all,participating}",
"labels_url": "https://api.github.com/repos/darkmatter/infra/labels{/name}",
"releases_url": "https://api.github.com/repos/darkmatter/infra/releases{/id}",
"deployments_url": "https://api.github.com/repos/darkmatter/infra/deployments",
"created_at": "2025-09-06T09:28:59Z",
"updated_at": "2026-06-03T14:06:12Z",
"pushed_at": "2026-06-03T15:05:06Z",
"git_url": "git://github.com/darkmatter/infra.git",
"ssh_url": "git@github.com:darkmatter/infra.git",
"clone_url": "https://github.com/darkmatter/infra.git",
"svn_url": "https://github.com/darkmatter/infra",
"homepage": null,
"size": 59144,
"stargazers_count": 0,
"watchers_count": 0,
"language": "Nix",
"has_issues": true,
"has_projects": true,
"has_downloads": true,
"has_wiki": true,
"has_pages": true,
"has_discussions": false,
"forks_count": 0,
"mirror_url": null,
"archived": false,
"disabled": false,
"open_issues_count": 2,
"license": null,
"allow_forking": false,
"is_template": false,
"web_commit_signoff_required": false,
"has_pull_requests": true,
"pull_request_creation_policy": "all",
"topics": [],
"visibility": "private",
"forks": 0,
"open_issues": 2,
"watchers": 0,
"default_branch": "main"
}
},
"_links": {
"self": {
"href": "https://api.github.com/repos/darkmatter/infra/pulls/21"
},
"html": {
"href": "https://github.com/darkmatter/infra/pull/21"
},
"issue": {
"href": "https://api.github.com/repos/darkmatter/infra/issues/21"
},
"comments": {
"href": "https://api.github.com/repos/darkmatter/infra/issues/21/comments"
},
"review_comments": {
"href": "https://api.github.com/repos/darkmatter/infra/pulls/21/comments"
},
"review_comment": {
"href": "https://api.github.com/repos/darkmatter/infra/pulls/comments{/number}"
},
"commits": {
"href": "https://api.github.com/repos/darkmatter/infra/pulls/21/commits"
},
"statuses": {
"href": "https://api.github.com/repos/darkmatter/infra/statuses/0f54ce4ae5f865cd6426d3f515cdc0de65d32557"
}
},
"author_association": "MEMBER",
"auto_merge": null,
"assignee": null,
"active_lock_reason": null
},
"thread": {
"node_id": "PRRT_kwDOPq3Cd86Gm4gz",
"comments": [
{
"url": "https://api.github.com/repos/darkmatter/infra/pulls/comments/3345370976",
"pull_request_review_id": 4414798997,
"id": 3345370976,
"node_id": "PRRC_kwDOPq3Cd87HZk9g",
"diff_hunk": "@@ -0,0 +1,262 @@\n+# render-homepage-config — generate a gethomepage/homepage dashboard config as a\n+# Kubernetes ConfigMap, from the same service SSOT used by gatus and the docs\n+# launcher.\n+#\n+# Run with: `nix run .#render-homepage-config`\n+#\n+# This is a *third renderer* over the service single-source-of-truth:\n+# * config/service-catalog.nix (`nix eval .#serviceCatalog`) — curated launcher\n+# * config/services.nix (`nix eval .#services`) — bun/container apps\n+# * darkmatter/gitops (apps/*.yaml + cloudflared) — k3s workloads\n+#\n+# Output: a single ConfigMap (name `homepage`, namespace `homepage`) carrying the\n+# four homepage config files as data keys (services/settings/widgets/bookmarks.yaml).\n+# Written to $HOMEPAGE_CONFIGMAP_OUT (default: $GITOPS_DIR/manifests/homepage/\n+# configmap.yaml). A GitHub Actions workflow regenerates this and opens a PR\n+# against darkmatter/gitops; ArgoCD then deploys it to the cluster.\n+#\n+# Env:\n+# INFRA_REPO_ROOT — infra repo root (default: git toplevel)\n+# GITOPS_DIR — darkmatter/gitops checkout (default: sibling ../gitops)\n+# HOMEPAGE_CONFIGMAP_OUT — output path (default: $GITOPS_DIR/manifests/homepage/configmap.yaml)\n+{ pkgs, ... }:\n+let\n+ app = pkgs.writeShellApplication {\n+ name = \"render-homepage-config\";\n+ runtimeInputs = with pkgs; [ jq yq-go coreutils git nix ];\n+ # SC2016: jq/yq filters legitimately contain literal `$foo` inside single\n+ # quotes — those are jq variables, not shell expansions.\n+ # SC2129: a few grouped redirects read clearer as individual appends.\n+ excludeShellChecks = [ \"SC2016\" \"SC2129\" ];\n+ text = ''\n+ set -euo pipefail\n+\n+ REPO_ROOT=\"''${INFRA_REPO_ROOT:-$(git rev-parse --show-toplevel)}\"\n+ GITOPS_DIR=\"''${GITOPS_DIR:-$REPO_ROOT/../gitops}\"\n+ OUT=\"''${HOMEPAGE_CONFIGMAP_OUT:-$GITOPS_DIR/manifests/homepage/configmap.yaml}\"\n+\n+ # ── Pull the service SSOT via flake outputs (don't re-parse Nix here) ──\n+ catalog_json=\"$(nix eval --json --no-warn-dirty \"$REPO_ROOT#serviceCatalog\")\"\n+ services_json=\"$(nix eval --json --no-warn-dirty \"$REPO_ROOT#services\")\"\n+\n+ # ── services.nix → catalog-shaped entries (group \"services\") ──────────\n+ # Mirrors render-inventory-index.nix so app deployments render alongside\n+ # the curated catalog under the \"Application services\" group.\n+ services_entries=\"$(echo \"$services_json\" | jq '\n+ to_entries\n+ | map({\n+ name: .key,\n+ title: .key,\n+ group: \"services\",\n+ url: (\"https://\" + .value.domain),\n+ description: (\"Application service (\" + (.value.runtime // \"bun\") + \") on \"\n+ + .value.machine + \"/\" + (.value.vm // .value.machine) + \".\")\n+ })\n+ ')\"\n+\n+ all_entries=\"$(jq -s '.[0].entries + .[1]' \\\n+ <(echo \"$catalog_json\") <(echo \"$services_entries\"))\"\n+\n+ # ── gitops discovery: ArgoCD apps (deduped by name) ───────────────────\n+ apps_json=\"[]\"\n+ if [ -d \"$GITOPS_DIR/apps\" ]; then\n+ apps_json=\"$(\n+ for f in \"$GITOPS_DIR\"/apps/*.yaml; do\n+ [ -e \"$f\" ] || continue\n+ # Collect chart/path across single- and multi-source Applications\n+ # into one array, then take the first non-null — avoids the YAML\n+ # splat multiplying a multi-source app into several rows.\n+ yq -o=json -I=0 '{\n+ \"name\": .metadata.name,\n+ \"ns\": (.spec.destination.namespace // \"\"),\n+ \"chart\":([.spec.source.chart, .spec.sources[].chart] | map(select(. != null)) | .[0] // \"\"),\n+ \"path\": ([.spec.source.path, .spec.sources[].path] | map(select(. != null)) | .[0] // \"\")\n+ }' \"$f\"\n+ done | jq -s 'unique_by(.name) | map(select(.ns != \"homepage\"))'\n+ )\"\n+ fi\n+\n+ # ── gitops discovery: cloudflared ingress → public hostnames ──────────\n+ # The in-cluster tunnel's ingress list is the authoritative map of which\n+ # hostname reaches which Service. `.data.\"config.yaml\"` is itself a YAML\n+ # string, so we parse it a second time. Namespace is the 2nd dotted label\n+ # of the service FQDN (svc-name.<ns>.svc.cluster.local).\n+ ingress_json=\"[]\"\n+ cf=\"$GITOPS_DIR/manifests/cloudflared/configmap.yaml\"\n+ if [ -f \"$cf\" ]; then\n+ ingress_json=\"$(yq '.data.\"config.yaml\"' \"$cf\" \\\n+ | yq -o=json -I=0 '[.ingress[] | select(.hostname) | {\"host\": .hostname, \"svc\": .service}]' \\\n+ | jq 'map(. + {ns: ((.svc | capture(\"^https?://[^.]+[.](?<ns>[^.]+)[.]svc\") | .ns) // \"\")})')\"",
"path": "nix/flake/apps/render-homepage-config.nix",
"commit_id": "6f350130be4c529882c57915a99d9c850d989fa0",
"original_commit_id": "6f350130be4c529882c57915a99d9c850d989fa0",
"user": {
"login": "Copilot",
"id": 175728472,
"node_id": "BOT_kgDOCnlnWA",
"avatar_url": "https://avatars.githubusercontent.com/in/946600?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/Copilot",
"html_url": "https://github.com/apps/copilot-pull-request-reviewer",
"followers_url": "https://api.github.com/users/Copilot/followers",
"following_url": "https://api.github.com/users/Copilot/following{/other_user}",
"gists_url": "https://api.github.com/users/Copilot/gists{/gist_id}",
"starred_url": "https://api.github.com/users/Copilot/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/Copilot/subscriptions",
"organizations_url": "https://api.github.com/users/Copilot/orgs",
"repos_url": "https://api.github.com/users/Copilot/repos",
"events_url": "https://api.github.com/users/Copilot/events{/privacy}",
"received_events_url": "https://api.github.com/users/Copilot/received_events",
"type": "Bot",
"user_view_type": "public",
"site_admin": false
},
"body": "The cloudflared ConfigMap embeds its real config as a multi-line string. `yq '.data.\"config.yaml\"'` will emit that string as a YAML block scalar (`|-`), which breaks the second `yq` parse. Use raw output (`-r`) for the first extraction so the piped content is valid YAML.",
"created_at": "2026-06-03T01:14:12Z",
"updated_at": "2026-06-03T01:14:12Z",
"html_url": "https://github.com/darkmatter/infra/pull/21#discussion_r3345370976",
"pull_request_url": "https://api.github.com/repos/darkmatter/infra/pulls/21",
"_links": {
"self": {
"href": "https://api.github.com/repos/darkmatter/infra/pulls/comments/3345370976"
},
"html": {
"href": "https://github.com/darkmatter/infra/pull/21#discussion_r3345370976"
},
"pull_request": {
"href": "https://api.github.com/repos/darkmatter/infra/pulls/21"
}
},
"reactions": {
"url": "https://api.github.com/repos/darkmatter/infra/pulls/comments/3345370976/reactions",
"total_count": 0,
"+1": 0,
"-1": 0,
"laugh": 0,
"hooray": 0,
"confused": 0,
"heart": 0,
"rocket": 0,
"eyes": 0
},
"start_line": null,
"original_start_line": 87,
"start_side": "RIGHT",
"line": null,
"original_line": 89,
"side": "RIGHT",
"author_association": "NONE",
"original_position": 89,
"position": 1,
"subject_type": "line"
}
]
},
"updated_at": "2026-06-03T08:05:08-07:00",
"repository": {
"id": 1051574903,
"node_id": "R_kgDOPq3Cdw",
"name": "infra",
"full_name": "darkmatter/infra",
"private": true,
"owner": {
"login": "darkmatter",
"id": 17834193,
"node_id": "MDEyOk9yZ2FuaXphdGlvbjE3ODM0MTkz",
"avatar_url": "https://avatars.githubusercontent.com/u/17834193?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/darkmatter",
"html_url": "https://github.com/darkmatter",
"followers_url": "https://api.github.com/users/darkmatter/followers",
"following_url": "https://api.github.com/users/darkmatter/following{/other_user}",
"gists_url": "https://api.github.com/users/darkmatter/gists{/gist_id}",
"starred_url": "https://api.github.com/users/darkmatter/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/darkmatter/subscriptions",
"organizations_url": "https://api.github.com/users/darkmatter/orgs",
"repos_url": "https://api.github.com/users/darkmatter/repos",
"events_url": "https://api.github.com/users/darkmatter/events{/privacy}",
"received_events_url": "https://api.github.com/users/darkmatter/received_events",
"type": "Organization",
"user_view_type": "public",
"site_admin": false
},
"html_url": "https://github.com/darkmatter/infra",
"description": "Versioned infra repo",
"fork": false,
"url": "https://api.github.com/repos/darkmatter/infra",
"forks_url": "https://api.github.com/repos/darkmatter/infra/forks",
"keys_url": "https://api.github.com/repos/darkmatter/infra/keys{/key_id}",
"collaborators_url": "https://api.github.com/repos/darkmatter/infra/collaborators{/collaborator}",
"teams_url": "https://api.github.com/repos/darkmatter/infra/teams",
"hooks_url": "https://api.github.com/repos/darkmatter/infra/hooks",
"issue_events_url": "https://api.github.com/repos/darkmatter/infra/issues/events{/number}",
"events_url": "https://api.github.com/repos/darkmatter/infra/events",
"assignees_url": "https://api.github.com/repos/darkmatter/infra/assignees{/user}",
"branches_url": "https://api.github.com/repos/darkmatter/infra/branches{/branch}",
"tags_url": "https://api.github.com/repos/darkmatter/infra/tags",
"blobs_url": "https://api.github.com/repos/darkmatter/infra/git/blobs{/sha}",
"git_tags_url": "https://api.github.com/repos/darkmatter/infra/git/tags{/sha}",
"git_refs_url": "https://api.github.com/repos/darkmatter/infra/git/refs{/sha}",
"trees_url": "https://api.github.com/repos/darkmatter/infra/git/trees{/sha}",
"statuses_url": "https://api.github.com/repos/darkmatter/infra/statuses/{sha}",
"languages_url": "https://api.github.com/repos/darkmatter/infra/languages",
"stargazers_url": "https://api.github.com/repos/darkmatter/infra/stargazers",
"contributors_url": "https://api.github.com/repos/darkmatter/infra/contributors",
"subscribers_url": "https://api.github.com/repos/darkmatter/infra/subscribers",
"subscription_url": "https://api.github.com/repos/darkmatter/infra/subscription",
"commits_url": "https://api.github.com/repos/darkmatter/infra/commits{/sha}",
"git_commits_url": "https://api.github.com/repos/darkmatter/infra/git/commits{/sha}",
"comments_url": "https://api.github.com/repos/darkmatter/infra/comments{/number}",
"issue_comment_url": "https://api.github.com/repos/darkmatter/infra/issues/comments{/number}",
"contents_url": "https://api.github.com/repos/darkmatter/infra/contents/{+path}",
"compare_url": "https://api.github.com/repos/darkmatter/infra/compare/{base}...{head}",
"merges_url": "https://api.github.com/repos/darkmatter/infra/merges",
"archive_url": "https://api.github.com/repos/darkmatter/infra/{archive_format}{/ref}",
"downloads_url": "https://api.github.com/repos/darkmatter/infra/downloads",
"issues_url": "https://api.github.com/repos/darkmatter/infra/issues{/number}",
"pulls_url": "https://api.github.com/repos/darkmatter/infra/pulls{/number}",
"milestones_url": "https://api.github.com/repos/darkmatter/infra/milestones{/number}",
"notifications_url": "https://api.github.com/repos/darkmatter/infra/notifications{?since,all,participating}",
"labels_url": "https://api.github.com/repos/darkmatter/infra/labels{/name}",
"releases_url": "https://api.github.com/repos/darkmatter/infra/releases{/id}",
"deployments_url": "https://api.github.com/repos/darkmatter/infra/deployments",
"created_at": "2025-09-06T09:28:59Z",
"updated_at": "2026-06-03T14:06:12Z",
"pushed_at": "2026-06-03T15:05:06Z",
"git_url": "git://github.com/darkmatter/infra.git",
"ssh_url": "git@github.com:darkmatter/infra.git",
"clone_url": "https://github.com/darkmatter/infra.git",
"svn_url": "https://github.com/darkmatter/infra",
"homepage": null,
"size": 59144,
"stargazers_count": 0,
"watchers_count": 0,
"language": "Nix",
"has_issues": true,
"has_projects": true,
"has_downloads": true,
"has_wiki": true,
"has_pages": true,
"has_discussions": false,
"forks_count": 0,
"mirror_url": null,
"archived": false,
"disabled": false,
"open_issues_count": 2,
"license": null,
"allow_forking": false,
"is_template": false,
"web_commit_signoff_required": false,
"has_pull_requests": true,
"pull_request_creation_policy": "all",
"topics": [],
"visibility": "private",
"forks": 0,
"open_issues": 2,
"watchers": 0,
"default_branch": "main",
"custom_properties": {}
},
"organization": {
"login": "darkmatter",
"id": 17834193,
"node_id": "MDEyOk9yZ2FuaXphdGlvbjE3ODM0MTkz",
"url": "https://api.github.com/orgs/darkmatter",
"repos_url": "https://api.github.com/orgs/darkmatter/repos",
"events_url": "https://api.github.com/orgs/darkmatter/events",
"hooks_url": "https://api.github.com/orgs/darkmatter/hooks",
"issues_url": "https://api.github.com/orgs/darkmatter/issues",
"members_url": "https://api.github.com/orgs/darkmatter/members{/member}",
"public_members_url": "https://api.github.com/orgs/darkmatter/public_members{/member}",
"avatar_url": "https://avatars.githubusercontent.com/u/17834193?v=4",
"description": ""
},
"enterprise": {
"id": 469843,
"slug": "darkmatter",
"name": "darkmatter",
"node_id": "E_kgDOAAcrUw",
"avatar_url": "https://avatars.githubusercontent.com/b/469843?v=4",
"description": "",
"website_url": "darkmatter.io",
"html_url": "https://github.com/enterprises/darkmatter",
"created_at": "2025-09-07T16:01:00Z",
"updated_at": "2026-05-09T15:34:55Z"
},
"sender": {
"login": "czxtm",
"id": 1325802,
"node_id": "MDQ6VXNlcjEzMjU4MDI=",
"avatar_url": "https://avatars.githubusercontent.com/u/1325802?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/czxtm",
"html_url": "https://github.com/czxtm",
"followers_url": "https://api.github.com/users/czxtm/followers",
"following_url": "https://api.github.com/users/czxtm/following{/other_user}",
"gists_url": "https://api.github.com/users/czxtm/gists{/gist_id}",
"starred_url": "https://api.github.com/users/czxtm/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/czxtm/subscriptions",
"organizations_url": "https://api.github.com/users/czxtm/orgs",
"repos_url": "https://api.github.com/users/czxtm/repos",
"events_url": "https://api.github.com/users/czxtm/events{/privacy}",
"received_events_url": "https://api.github.com/users/czxtm/received_events",
"type": "User",
"user_view_type": "public",
"site_admin": false
},
"installation": {
"id": 131074261,
"node_id": "MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uMTMxMDc0MjYx"
}
}