{"id":50956837,"url":"https://github.com/vquie/kausal","last_synced_at":"2026-06-18T08:30:42.652Z","repository":{"id":365507105,"uuid":"1254547463","full_name":"vquie/kausal","owner":"vquie","description":null,"archived":false,"fork":false,"pushed_at":"2026-06-17T16:34:27.000Z","size":195,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-17T17:31:25.966Z","etag":null,"topics":["developer-tools","devops","graph","k8s","kubernetes","observability","react","typescript","visualization"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vquie.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-30T17:50:58.000Z","updated_at":"2026-06-17T16:34:55.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/vquie/kausal","commit_stats":null,"previous_names":["vquie/kausal"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/vquie/kausal","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vquie%2Fkausal","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vquie%2Fkausal/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vquie%2Fkausal/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vquie%2Fkausal/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vquie","download_url":"https://codeload.github.com/vquie/kausal/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vquie%2Fkausal/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34483274,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-18T02:00:06.871Z","response_time":128,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["developer-tools","devops","graph","k8s","kubernetes","observability","react","typescript","visualization"],"created_at":"2026-06-18T08:30:40.726Z","updated_at":"2026-06-18T08:30:42.644Z","avatar_url":"https://github.com/vquie.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"left\"\u003e\n  \u003cimg src=\"apps/client/src/assets/logo.png\" alt=\"Kausal logo\" width=\"280\"\u003e\n\u003c/p\u003e\n\nKausal is a local-first Kubernetes visualization tool that explains why resources look the way they do by combining ownership, selector, exposure, ingress, scaling, reference, and `managedFields` data into a single graph.\n\nKausal is published on GitHub under the MIT License.\n\n## Architecture\n\n- `apps/server/`: Express API in TypeScript. It reads supported Kubernetes resources with a read-only ServiceAccount, derives graph edges, summarizes `managedFields`, and exposes the API.\n- `apps/client/`: React app with a three-column layout: resource list, graph canvas, detail panel.\n- `deploy/dev/k8s/`: Development-only Kubernetes manifests for a local Kubernetes cluster.\n- `Dockerfile`: Multi-stage Node build that serves the built React app from the backend container.\n\nThe backend supports:\n\n- `GET /api/healthz`\n- `GET /api/resources`\n- `GET /api/graph`\n- `GET /api/resource/:namespace/:kind/:name`\n\n## Supported resources\n\n- Namespace\n- Deployment\n- ReplicaSet\n- Pod\n- Service\n- Ingress\n- ConfigMap\n- Secret references inferred from workloads\n- HorizontalPodAutoscaler\n\n## Derived relationships\n\n- `owns`\n- `selects`\n- `exposes`\n- `scales`\n- `references`\n- `ingress-routes-to`\n\n## Assumptions\n\n- The primary run mode is inside Kubernetes. The app is intended to run in a local Kubernetes cluster and read the cluster through its ServiceAccount.\n- The manifests in `deploy/dev/k8s/` are for development only. They are intentionally local-cluster oriented and not a production deployment baseline.\n- Secret contents and Secret metadata are never returned by the API or rendered in the UI. Secret nodes are inferred from workload references instead of being fetched from the Kubernetes API.\n- The initial graph layout is deterministic and simple. It is meant for comprehension, not for perfect graph aesthetics.\n- Ingress is optional because local Ingress availability depends on the local cluster setup.\n\n## Local development\n\nInstall dependencies:\n\n```bash\nnpm install\n```\n\nRun the backend:\n\n```bash\nnpm run dev:server\n```\n\nRun the frontend:\n\n```bash\nnpm run dev:client\n```\n\nThe Vite frontend proxies `/api` to `http://localhost:8080`.\n\n## Build the image\n\nFrom the repository root:\n\n```bash\ndocker build -t kausal:dev .\n```\n\n## Release flow\n\nPushing a Git tag triggers the GitHub release workflow in `.github/workflows/release.yml`.\n\nThe workflow:\n\n- builds the root `Dockerfile`\n- pushes the image to `ghcr.io/vquie/kausal` with version aliases\n- creates a GitHub release\n- generates release notes from the changes since the previous tag\n\nSupported release tags:\n\n- `v1.2.3`\n- `1.2.3`\n\nFor either form, the workflow publishes:\n\n- `v1.2.3`\n- `v1.2`\n- `v1`\n- `1.2.3`\n- `1.2`\n- `1`\n- `latest`\n\nExample:\n\n```bash\ngit tag v0.1.0\ngit push origin v0.1.0\n```\n\n## Make the image available to the local Kubernetes cluster\n\nSome local Kubernetes setups expose the local Docker image store directly to the cluster. If your environment uses the same image store, no extra import step is needed after `docker build`.\n\nIf the Pod cannot pull `kausal:dev`, rebuild and confirm the image exists locally:\n\n```bash\ndocker images | grep kausal\n```\n\n## Deploy to Kubernetes\n\nApply the manifests:\n\n```bash\nkubectl apply -f deploy/dev/k8s/namespace.yaml\nkubectl apply -f deploy/dev/k8s/serviceaccount.yaml\nkubectl apply -f deploy/dev/k8s/clusterrole.yaml\nkubectl apply -f deploy/dev/k8s/clusterrolebinding.yaml\nkubectl apply -f deploy/dev/k8s/deployment.yaml\nkubectl apply -f deploy/dev/k8s/service.yaml\nkubectl apply -f deploy/dev/k8s/networkpolicy.yaml\n```\n\nOptional Ingress:\n\n```bash\nkubectl apply -f deploy/dev/k8s/ingress.yaml\n```\n\nCheck rollout:\n\n```bash\nkubectl -n kausal rollout status deployment/kausal\nkubectl -n kausal get pods\n```\n\n## Access the app\n\nUse port-forwarding:\n\n```bash\nkubectl -n kausal port-forward svc/kausal 8080:8080\n```\n\nThen open:\n\n```text\nhttp://localhost:8080\n```\n\n## Troubleshooting\n\nCheck logs:\n\n```bash\nkubectl -n kausal logs deployment/kausal\n```\n\nCheck health:\n\n```bash\nkubectl -n kausal port-forward svc/kausal 8080:8080\ncurl http://localhost:8080/api/healthz\n```\n\nCheck RBAC:\n\n```bash\nkubectl auth can-i list pods --as=system:serviceaccount:kausal:kausal --all-namespaces\nkubectl auth can-i list deployments.apps --as=system:serviceaccount:kausal:kausal --all-namespaces\nkubectl auth can-i list ingresses.networking.k8s.io --as=system:serviceaccount:kausal:kausal --all-namespaces\nkubectl auth can-i list horizontalpodautoscalers.autoscaling --as=system:serviceaccount:kausal:kausal --all-namespaces\n```\n\nIf `/api/healthz` returns an error, verify:\n\n- The `kausal` ServiceAccount is mounted into the Pod.\n- The ClusterRoleBinding points to `kausal/kausal`.\n- The local cluster actually exposes the Kubernetes API to in-cluster Pods.\n- The image tag in `deploy/dev/k8s/deployment.yaml` matches the image you built locally.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvquie%2Fkausal","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvquie%2Fkausal","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvquie%2Fkausal/lists"}