{"id":18510674,"url":"https://github.com/operator-framework/combo","last_synced_at":"2026-03-12T00:34:01.143Z","repository":{"id":40380670,"uuid":"411761150","full_name":"operator-framework/combo","owner":"operator-framework","description":null,"archived":false,"fork":false,"pushed_at":"2022-05-13T15:34:21.000Z","size":174,"stargazers_count":8,"open_issues_count":7,"forks_count":15,"subscribers_count":15,"default_branch":"main","last_synced_at":"2025-05-30T00:41:42.326Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/operator-framework.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":"CODEOWNERS","security":null,"support":null}},"created_at":"2021-09-29T17:04:25.000Z","updated_at":"2022-05-06T23:48:56.000Z","dependencies_parsed_at":"2022-08-09T18:51:15.149Z","dependency_job_id":null,"html_url":"https://github.com/operator-framework/combo","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/operator-framework/combo","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/operator-framework%2Fcombo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/operator-framework%2Fcombo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/operator-framework%2Fcombo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/operator-framework%2Fcombo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/operator-framework","download_url":"https://codeload.github.com/operator-framework/combo/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/operator-framework%2Fcombo/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30408506,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-11T22:36:59.286Z","status":"ssl_error","status_checked_at":"2026-03-11T22:36:57.544Z","response_time":84,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-06T15:24:22.692Z","updated_at":"2026-03-12T00:34:01.126Z","avatar_url":"https://github.com/operator-framework.png","language":"Go","readme":"# combo\n\n`combo` is a [Kubernetes controller](https://kubernetes.io/docs/concepts/architecture/controller/) that generates and applies resources for __all combinations__ of a manifest template and its arguments.\n\n## What on earth does \"all combinations\" mean!?\n\nFor example, say `combo` is given a template containing 1 _parameter_  -- i.e. distinct token to replaced -- and 2 _arguments_  for that parameter (value to replace a parameter with), then `combo` will output 2 _evaluations_ (one for each argument).\n\ne.g.\n\n_template:_\n\n```yaml\nPARAM_1\n```\n\n_arguments:_\n\n```\nPARAM_1:\n- a\n- b\n```\n\n_evaluations:_\n\n```yaml\n---\na\n---\nb\n```\n\nSimple enough, right? What about something more advanced...\n\nSuppose we give `combo` a template with 2 parameters and 3 arguments for each parameter.\n\ne.g.\n\n_template:_\n\n```yaml\nPARAM_1: PARAM_2\n```\n_arguments:_\n\n```yaml\nPARAM_1:\n- a\n- b\nPARAM_2:\n- c\n- d\n- e\n```\n\n_evaluations:_\n\n```yaml\n---\na: c\n---\na: d\n---\na: e\n---\nb: c\n---\nb: d\n---\nb: e\n```\n\n## Wait, can't Helm do this?\n\nIt could, __but__ getting this experience from Helm would require:\n\n- the use of nested Go Template loops\n- carrying along the rest of the ecosystem; e.g. I don't want to think about Helm charts for something this simple\n\n## Can I generate combinations locally?\n\nYes! There is a built in CLI interaction via the binary. Let's look at the same example we used for the controller in this context.\n\nFirst, create a simple YAML file that defines two arguments.\n\n```yaml\n# ./sample_input.yaml\nPARAM_1: PARAM_2\n```\n\nNext, go ahead and run the `eval` subcommand.\n\n```shell\nmake build-cli\n./combo eval -r PARAM_1=a,b -r PARAM_2=c,d,e sample_input.yaml\n```\n\nThis will run the same logic that the controller utilizes to generate combinations and output them to stdout. The above command will produce the following:\n\n```yaml\n---\na: c\n---\na: d\n---\na: e\n---\nb: c\n---\nb: d\n---\nb: e\n```\n\n## Primary use cases\n\nTo parameterize RBAC and other namespace-scoped resources so they can be stamped out as necessary later on.\n\n```shell\n$ cat \u003c\u003cEOF | kubectl create -f -\napiVersion: combo.io/v1alpha1\nkind: Template\nmetadata:\n  name: feature\nspec:\n  body: |\n    ---\n    apiVersion: rbac.authorization.k8s.io/v1\n    kind: RoleBinding\n    metadata:\n      name: feature-controller\n      namespace: TARGET_NAMESPACE\n    subjects:\n    - kind: ServiceAccount\n      name: controller\n      namespace: feature\n    roleRef:\n      kind: ClusterRole\n      name: feature-controller\n      apiGroup: rbac.authorization.k8s.io\n    ---\n    apiVersion: rbac.authorization.k8s.io/v1\n    kind: RoleBinding\n    metadata:\n      generateName: feature-user-\n      namespace: TARGET_NAMESPACE\n    subjects:\n    - kind: Group\n      name: TARGET_GROUP\n      namespace: TARGET_NAMESPACE\n      apiGroup: rbac.authorization.k8s.io\n    roleRef:\n      kind: ClusterRole\n      name: feature-user\n      apiGroup: rbac.authorization.k8s.io\n  parameters:\n  - TARGET_GROUP\n  - TARGET_NAMESPACE\nEOF\n```\n\nAssuming the existence of the `feature-controller` and `feature-user` `ClusterRoles` as well as the `feature`, `staging`, and `prod` `Namespaces`, instantiate all resource/argument combinations with a `Combination`:\n\n```shell\n$ cat \u003c\u003cEOF | kubectl create -f -\napiVersion: combo.io/v1alpha1\nkind: Combination\nmetadata:\n  name: enable-feature\nspec:\n  template: feature\n  arguments:\n  - key: TARGET_GROUP\n    values:\n    - \"sre\"\n    - \"system:serviceaccounts:ci\"\n  - key: TARGET_NAMESPACE\n    values:\n    - staging\n    - prod\nEOF\n```\n\ncombo then surfaces the evaluated template in the status:\n\n```shell\n$ kubectl get combination -o yaml\napiVersion: combo.io/v1alpha1\nkind: Combination\nmetadata:\n  name: enable-feature\nspec:\n  template:\n    name: feature\n  arguments:\n  - key: TARGET_GROUP\n    values:\n    - \"sre\"\n    - \"system:serviceaccounts:ci\"\n  - key: TARGET_NAMESPACE\n    values:\n    - staging\n    - prod\nstatus:\n  evaluated:\n  - apiVersion: rbac.authorization.k8s.io/v1\n    kind: RoleBinding\n    metadata:\n      name: feature-controller\n      namespace: staging\n    subjects:\n    - kind: ServiceAccount\n      name: controller\n      namespace: feature\n    roleRef:\n      kind: ClusterRole\n      name: feature-controller\n      apiGroup: rbac.authorization.k8s.io\n  - apiVersion: rbac.authorization.k8s.io/v1\n    kind: RoleBinding\n    metadata:\n      generateName: feature-user-\n      namespace: staging\n    subjects:\n    - kind: Group\n      name: sre\n      namespace: staging\n      apiGroup: rbac.authorization.k8s.io\n    roleRef:\n      kind: ClusterRole\n      name: feature-user\n      apiGroup: rbac.authorization.k8s.io\n      ...\n```\n\n## Ulterior motives\n\nOur \"hidden\" agenda with `combo` is for it to:\n\n- serve as an example of best-practices when building operators\n- be used to dog food operator-framework packaging formats (e.g. OLM, rukpak, etc)\n- become a dependency of operators that require post-install configuration (e.g. RBAC scoping, secret creation, etc)\n- serve as a cruft-free way to up-skill new maintainers through easy contributions\n\n## Planned Features\n\nThe combo project is currently in active development and you can find up-to-date, tracked work in the [Combo Project Board][roadmap].\n\nIntroducing or discussing new roadmap items can be done by opening an issue.\n\nBefore opening an issue, it's recommended to check whether a similar issue is already open to avoid duplicating roadmap efforts.\n\n[roadmap]: \u003chttps://github.com/operator-framework/combo/projects/1\u003e\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foperator-framework%2Fcombo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foperator-framework%2Fcombo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foperator-framework%2Fcombo/lists"}