{"id":22271578,"url":"https://github.com/appthrust/tokenaut","last_synced_at":"2025-03-25T15:53:34.947Z","repository":{"id":254070588,"uuid":"845394276","full_name":"appthrust/tokenaut","owner":"appthrust","description":"tokenaut is a Kubernetes controller for managing GitHub App Installation Access Tokens (server-to-server tokens, ghs).","archived":false,"fork":false,"pushed_at":"2025-02-20T23:00:55.000Z","size":153,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-19T13:45:04.924Z","etag":null,"topics":["github-apps","kubernetes","kubernetes-operator"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/appthrust.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}},"created_at":"2024-08-21T06:58:52.000Z","updated_at":"2025-02-20T23:00:58.000Z","dependencies_parsed_at":"2025-02-20T23:25:46.621Z","dependency_job_id":"e36786d0-20da-4337-bb0e-baacb28aafda","html_url":"https://github.com/appthrust/tokenaut","commit_stats":null,"previous_names":["appthrust/tokenaut"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appthrust%2Ftokenaut","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appthrust%2Ftokenaut/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appthrust%2Ftokenaut/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appthrust%2Ftokenaut/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/appthrust","download_url":"https://codeload.github.com/appthrust/tokenaut/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245495820,"owners_count":20624807,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["github-apps","kubernetes","kubernetes-operator"],"created_at":"2024-12-03T12:12:36.845Z","updated_at":"2025-03-25T15:53:34.926Z","avatar_url":"https://github.com/appthrust.png","language":"Go","readme":"# tokenaut: GitHub App Installation Access Token Controller\n\n[![Docker Repository on Quay](https://quay.io/repository/appthrust/tokenaut/status \"Docker Repository on Quay\")](https://quay.io/repository/appthrust/tokenaut)\n\ntokenaut is a controller for managing GitHub App Installation Access Tokens (server-to-server tokens, ghs).\n\n## Problem Solved\n\nGitHub Apps issue relatively short-lived Installation Access Tokens. These tokens are often needed for tools like ArgoCD, FluxCD, or Crossplane provider-github. (While ArgoCD and provider-github support GitHub App private keys, you might prefer not to distribute private keys to various pods.) In such cases, it's necessary to maintain an active token that's always within its validity period. This project aims to solve this challenge using the Kubernetes controller pattern.\n\n## Controller's Role\n\nThe controller periodically recreates the GitHub token contained in the Secret resource to prevent it from expiring, keeping the Secret resource up-to-date.\n\n![](docs/assets/fig1.png)\n\n## Mechanism\n\nA Secret resource is created based on the InstallationAccessToken resource. When there's a change to the InstallationAccessToken resource, the Secret resource is updated.\n\n![](docs/assets/fig2.png)\n\nTo operate this controller, you need the GitHub App's private key. First, create a Secret containing this key with the name \"github-app-private-key\":\n\n```yaml\napiVersion: v1\nkind: Secret\nmetadata:\n  name: github-app-private-key\n  namespace: default\ntype: tokenaut.appthrust.io/private-key\nstringData:\n  privateKey: |\n    -----BEGIN RSA PRIVATE KEY-----\n    ...\n    -----END RSA PRIVATE KEY-----\n```\n\n\u003e NOTE: The name and namespace can be customized using the \"Explicit Private Key\" method described later. This allows handling multiple private keys or using preferred names.\n\nNext, create the InstallationAccessToken resource, which is the source for the Secret. This resource requires at least two fields: appId and installationId, specifying which GitHub App and which installation to use.\n\n```yaml\napiVersion: tokenaut.appthrust.io/v1alpha1\nkind: InstallationAccessToken\nmetadata:\n  name: our-github-token\n  namespace: default\nspec:\n  appId: \"12345\"\n  installationId: \"1234567890\"\n```\n\nWhen the controller discovers this InstallationAccessToken resource, it creates a Secret like this:\n\n```yaml\napiVersion: v1\nkind: Secret\nmetadata:\n  name: our-github-token\n  namespace: default\ntype: Opaque\nstringData:\n  token: ghs_16C7e42F292c6912E7710c838347Ae178B4a\n```\n\nBy default, the created Secret follows these simple rules:\n\n- `metadata.name`: Inherited from the InstallationAccessToken's `metadata.name`.\n- `metadata.namespace`: Inherited from the InstallationAccessToken's `metadata.namespace`. The Secret is created in the same namespace.\n- `data.token`: Contains the Base64 encoded token directly.\n\n\u003e NOTE: This behavior can be modified using the \"Custom Secret\" method described below.\n\n## Installation\n\ntokenaut is a Kubernetes controller for managing GitHub App Installation Access Tokens. To install the tokenaut Helm chart, use the following command:\n\n```bash\nhelm install my-tokenaut oci://quay.io/appthrust/tokenaut-helm/tokenaut --version 0.1.0\n```\n\n## Configuration\n\nThe following table lists the configurable parameters of the tokenaut chart and their default values.\n\n| Parameter | Description | Default |\n|-----------|-------------|---------|\n| `controllerManager.replicas` | Number of tokenaut controller replicas | `1` |\n| `controllerManager.manager.image.repository` | Image repository | `quay.io/appthrust/tokenaut` |\n| `controllerManager.manager.image.tag` | Image tag | `v0.1.0` |\n| `controllerManager.manager.args.enable-http2` | Enable HTTP/2 for the metrics and webhook servers | `false` |\n| `controllerManager.manager.args.health-probe-bind-address` | The address the probe endpoint binds to | `\":8081\"` |\n| `controllerManager.manager.args.leader-elect` | Enable leader election for controller manager | `true` |\n| `controllerManager.manager.args.metrics-bind-address` | The address the metrics endpoint binds to | `\"0\"` |\n| `controllerManager.manager.args.metrics-secure` | Serve metrics endpoint securely via HTTPS | `true` |\n| `controllerManager.manager.args.token-refresh-interval` | The interval at which to refresh the GitHub token | `\"50m\"` |\n| `controllerManager.manager.args.zap-devel` | Enable Zap development mode | `true` |\n| `controllerManager.manager.args.zap-encoder` | Zap log encoding | `\"console\"` |\n| `controllerManager.manager.args.zap-log-level` | Zap log level | `\"info\"` |\n| `controllerManager.manager.args.zap-stacktrace-level` | Zap stacktrace capture level | `\"error\"` |\n| `controllerManager.manager.args.zap-time-encoding` | Zap time encoding | `\"epoch\"` |\n| `controllerManager.manager.extraArgs` | Additional arguments to pass to the manager | `[]` |\n| `controllerManager.manager.resources.limits.cpu` | CPU resource limit | `\"500m\"` |\n| `controllerManager.manager.resources.limits.memory` | Memory resource limit | `\"128Mi\"` |\n| `controllerManager.manager.resources.requests.cpu` | CPU resource request | `\"10m\"` |\n| `controllerManager.manager.resources.requests.memory` | Memory resource request | `\"64Mi\"` |\n| `controllerManager.manager.containerSecurityContext.allowPrivilegeEscalation` | Allow privilege escalation for the container | `false` |\n| `controllerManager.manager.containerSecurityContext.capabilities.drop` | Linux capabilities to drop | `[\"ALL\"]` |\n\n### Customizing the Installation\n\nTo customize the installation, you can create a `values.yaml` file with your desired configurations:\n\n```yaml\ncontrollerManager:\n  replicas: 2\n  manager:\n    args:\n      token-refresh-interval: \"30m\"\n    resources:\n      limits:\n        cpu: \"1\"\n        memory: \"256Mi\"\n```\n\nThen, use this file during installation:\n\n```bash\nhelm install my-tokenaut oci://quay.io/appthrust/tokenaut-helm/tokenaut --version 0.1.0 -f values.yaml\n```\n\nAlternatively, you can override values directly in the command line:\n\n```bash\nhelm install my-tokenaut oci://quay.io/appthrust/tokenaut-helm/tokenaut --version 0.1.0 --set controllerManager.replicas=2\n```\n\n## Post-Installation\n\nAfter installation, you'll need to create a Secret containing your GitHub App's private key and a CustomResource (CR) for the InstallationAccessToken. Refer to the Usage section for more details on how to set these up.\n\n## Explicit Private Key\n\nBy default, the controller looks for a Secret named \"github-app-private-key\" in the \"default\" namespace and tries to recognize its \"privateKey\" field as the private key.\n\nYou can explicitly specify the private key if you want to:\n\n- Use a different `metadata.name` for the private key Secret.\n- Use a namespace other than \"default\".\n- Use a field name other than \"privateKey\".\n- Use multiple private keys.\n\nTo explicitly specify the private key, set `spec.privateKeyRef` in the InstallationAccessToken. For example, to use a Secret named \"my-key\":\n\n```diff\n apiVersion: tokenaut.appthrust.io/v1alpha1\n kind: InstallationAccessToken\n metadata:\n   name: our-github-token\n   namespace: default\n spec:\n   appId: \"12345\"\n   installationId: \"1234567890\"\n+  privateKeyRef:\n+    name: my-key\n```\n\nTo specify the namespace and field name as well:\n\n```diff\n apiVersion: tokenaut.appthrust.io/v1alpha1\n kind: InstallationAccessToken\n metadata:\n   name: our-github-token\n   namespace: default\n spec:\n   appId: \"12345\"\n   installationId: \"1234567890\"\n+  privateKeyRef:\n+    name: my-key\n+    namespace: my-space\n+    key: pem\n```\n\nThis specification will look for a Secret with the following structure:\n\n```yaml\napiVersion: v1\nkind: Secret\nmetadata:\n  name: my-key\n  namespace: my-space\ntype: tokenaut.appthrust.io/private-key\nstringData:\n  pem: ...snip...\n```\n\n## Custom Secret\n\nWhen converting InstallationAccessToken to Secret, the controller follows these rules:\n\n1. Copy `metadata.name` from InstallationAccessToken to Secret's `metadata.name`.\n2. Copy `metadata.namespace` from InstallationAccessToken to Secret's `metadata.namespace`.\n3. Write the Base64 encoded token to Secret's `data.token`.\n\nThis default behavior can be changed using `spec.template` in the InstallationAccessToken.\n\nFor example, to store the token in a \"password\" field:\n\n```diff\n apiVersion: tokenaut.appthrust.io/v1alpha1\n kind: InstallationAccessToken\n metadata:\n   name: our-github-token\n   namespace: default\n spec:\n   appId: \"12345\"\n   installationId: \"1234567890\"\n+  template:\n+    data:\n+      password: \"{{ .Token }}\"\n```\n\nThis generates a Secret like:\n\n```yaml\napiVersion: v1\nkind: Secret\nmetadata:\n  name: our-github-token\n  namespace: default\ntype: Opaque\ndata:\n  password: \"(Base64 encoded token)\"\n```\n\nTo change the name or namespace, specify them in the template:\n\n```diff\n apiVersion: tokenaut.appthrust.io/v1alpha1\n kind: InstallationAccessToken\n metadata:\n   name: our-github-token\n   namespace: default\n spec:\n   appId: \"12345\"\n   installationId: \"1234567890\"\n   template:\n+    metadata:\n+      name: custom-secret-name\n+      namespace: custom-namespace\n     data:\n       password: \"{{ .Token }}\"\n```\n\nThis generates:\n\n```yaml\napiVersion: v1\nkind: Secret\nmetadata:\n  name: custom-secret-name\n  namespace: custom-namespace\ntype: Opaque\ndata:\n  password: \"(Base64 encoded token)\"\n```\n\nThe template can specify any field of a Secret object, including `type`:\n\n```diff\n apiVersion: tokenaut.appthrust.io/v1alpha1\n kind: InstallationAccessToken\n metadata:\n   name: our-github-token\n   namespace: default\n spec:\n   appId: \"12345\"\n   installationId: \"1234567890\"\n   template:\n     metadata:\n       name: custom-secret-name\n       namespace: custom-namespace\n+    type: my-custom-type\n     data:\n       password: \"{{ .Token }}\"\n```\n\nSometimes you might want to handle a string with an embedded token, such as a URL for `git clone`:\n\n```\nhttps://ghs_16C7e42F292c6912E7710c838347Ae178B4a@github.com/my-org/my-repo.git\n```\n\nYou can generate such a URL using `{{ .Token }}` for string interpolation:\n\n```diff\n apiVersion: tokenaut.appthrust.io/v1alpha1\n kind: InstallationAccessToken\n metadata:\n   name: our-github-token\n   namespace: default\n spec:\n   appId: \"12345\"\n   installationId: \"1234567890\"\n   template:\n     stringData:\n+      cloneUrl: \"https://{{ .Token }}@github.com/my-org/my-repo.git\"\n```\n\n## Access Token Scope\n\n\u003e NOTE: This feature is a future idea that may be implemented.\n\nBy default, the created access tokens have no scope settings. If you want to narrow the scope of access tokens by repository or permissions, you can specify this in `spec.scope` of the InstallationAccessToken.\n\n```diff\n apiVersion: tokenaut.appthrust.io/v1alpha1\n kind: InstallationAccessToken\n metadata:\n   name: our-github-token\n   namespace: default\n spec:\n   appId: \"12345\"\n   installationId: \"1234567890\"\n+  scope:\n+    repositories:\n+      - repo1\n+      - repo2\n+    permissions:\n+      contents: write\n+      metadata: read\n```\n\nThe configurable scopes are as follows:\n\n| Item | Description | Data Type |\n| --- | --- | --- |\n| repositories | Repository names | string[] |\n| repositoryIds | Repository IDs | int[] |\n| permissions | Permissions. For settable permissions, refer to: [GitHub Docs](https://docs.github.com/en/rest/apps/apps?apiVersion=2022-11-28#create-an-installation-access-token-for-an-app) | map[string]string |\n\n## Duplicate Token Elimination\n\n\u003e NOTE: This feature is a future idea that may be implemented.\n\nGitHub App installation access tokens have a limit of 10 per hour for each combination of user * app * scope. If this limit is exceeded, the oldest token is revoked. Therefore, it's desirable not to create duplicate tokens with the same role.\n\nTo solve this limitation, if a token with the same combination already exists, it will be reused. The token for reuse is stored as a normal Secret. As a marker, the `type` is set to `tokenaut.appthrust.io/access-token-cache`.\n\n```yaml\napiVersion: v1\nkind: Secret\nmetadata:\n  name: github-app-access-token-{random}\n  namespace: default\n  annotations:\n    tokenaut.appthrust.io/repositories: '[\"foo\",\"bar\"]'\n    tokenaut.appthrust.io/repository-ids: '[123,456]'\n    tokenaut.appthrust.io/permissions: '{\"contents\":\"write\",\"metadata\":\"read\"}'\ntype: tokenaut.appthrust.io/access-token-cache\nstringData:\n  token: \"ghs_16C7e42F292c6912E7710c838347Ae178B4a\"\n```\n\n\u003e NOTE: This design guarantees duplicate elimination at the cluster level. It does not consider eliminating duplicates across multiple clusters or between a cluster and non-Kubernetes systems. This design may be revisited from scratch.\n\n## Token Refresh Frequency\n\nGitHub App installation access tokens have a lifespan of 1 hour. The controller refreshes all tokens at a frequency of 50 minutes. This is to ensure that the token is always valid and to avoid the token becoming invalid during the update process. If you need to change the update frequency, you can specify `-token-refresh-interval` in the controller's command line arguments.\n\n## Manual Trigger for Token Update\n\nYou might want to update a token manually without waiting for an hour. In such cases, you can prompt the controller to update by making a change to the InstallationAccessToken object, such as changing its `metadata.annotations`.\n\n## Status\n\nThe `status` of an InstallationAccessToken includes the following information, which can be used for operational reference or automation:\n\n```yaml\nstatus:\n  conditions:\n    - type: Token\n      status: \"True\"\n      reason: Created\n      message: \"Token successfully created\"\n      lastTransitionTime: \"2023-04-01T12:00:00Z\"\n    - type: Secret\n      status: \"True\"\n      reason: Updated\n      message: \"Secret successfully created/updated\"\n      lastTransitionTime: \"2023-04-01T12:00:05Z\"\n    - type: Ready\n      status: \"True\"\n      reason: AllReady\n      message: \"InstallationAccessToken is ready for use\"\n      lastTransitionTime: \"2023-04-01T12:00:05Z\"\n  secretRef:\n    name: \"our-github-token\"\n    namespace: \"default\"\n  token:\n    expiresAt: \"2023-04-01T13:00:00Z\"\n    permissions:\n      issues: \"write\"\n      contents: \"read\"\n    repositorySelection: \"selected\"\n    repositories:\n      - \"octocat/Hello-World\"\n    repositoryIds:\n      - 1296269\n```\n\n### Conditions\n\n**type=Token**\n\n| Status | Reason | Message | Description |\n| --- | --- | --- | --- |\n| True | Created | Token successfully created | Token was successfully created |\n| False | Failed | Failed to create token: {error_message} | Failed to create token. Includes error message |\n| Unknown | Pending | Token creation in progress | Token creation is in progress |\n\n**type=Secret**\n\n| Status | Reason | Message | Description |\n| --- | --- | --- | --- |\n| True | Updated | Secret successfully created/updated | Secret resource was successfully created or updated |\n| False | Failed | Failed to create/update Secret: {error_message} | Failed to create or update Secret resource. Includes error message |\n| Unknown | Pending | Secret creation/update in progress | Secret resource creation or update is in progress |\n\n**type=Ready**\n\n| Status | Reason | Message | Description |\n| --- | --- | --- | --- |\n| True | AllReady | InstallationAccessToken is ready for use | Token has been generated and Secret resource has been successfully created/updated |\n| False | TokenNotReady | Token is not ready: {reason} | Token is not in a usable state. Includes reason |\n| False | SecretNotReady | Secret is not ready: {reason} | Secret resource is not in a usable state. Includes reason |\n| False | InvalidConfiguration | Invalid configuration: {details} | Resource configuration is invalid. Includes details |\n| Unknown | Pending | Resource reconciliation in progress | Resource reconciliation is in progress |\n\n## Secret Deletion\n\nWhen an InstallationAccessToken is deleted, the associated Secret is automatically deleted as well. This ensures that no orphaned Secrets are left in the cluster after an InstallationAccessToken is removed.\n\nThe deletion process follows these steps:\n\n1. When an InstallationAccessToken is marked for deletion, the controller initiates the cleanup process.\n2. The controller attempts to delete the associated Secret, as specified in the InstallationAccessToken's status.\n3. If the Secret deletion is successful or the Secret is not found (possibly already deleted), the controller proceeds with removing the InstallationAccessToken.\n4. If there's an error during the Secret deletion (other than \"not found\"), the controller will retry the operation.\n\nThis automatic cleanup ensures that your cluster remains tidy and that sensitive information (the access token) is properly removed when it's no longer needed.\n\nNote: Ensure that the controller has the necessary permissions to delete Secrets in the relevant namespaces. If you're using InstallationAccessTokens across different namespaces, you may need to adjust your RBAC settings accordingly.\n\n## Secret Metadata\n\nTo improve the manageability and traceability of Secrets created by tokenaut, we've implemented additional metadata for these Secrets. This metadata helps operators easily identify which Secrets are managed by tokenaut and track their relationship to InstallationAccessTokens.\n\n### Labels\n\nEach Secret created by tokenaut includes the following labels:\n\n- `app.kubernetes.io/managed-by: tokenaut`: Indicates that this Secret is managed by tokenaut.\n- `tokenaut.appthrust.io/installation-access-token: \u003cnamespace\u003e.\u003cname\u003e`: Identifies the specific InstallationAccessToken resource that this Secret is associated with, including its namespace to ensure uniqueness across the cluster.\n\n### Annotations\n\nThe following annotations are added to each Secret:\n\n- `tokenaut.appthrust.io/last-updated`: Timestamp of when the Secret was last updated.\n- `tokenaut.appthrust.io/app-id`: The GitHub App ID associated with this Secret.\n- `tokenaut.appthrust.io/installation-id`: The GitHub App Installation ID associated with this Secret.\n- `tokenaut.appthrust.io/source-namespace`: The namespace of the source InstallationAccessToken.\n- `tokenaut.appthrust.io/source-name`: The name of the source InstallationAccessToken.\n\n### Use Cases\n\nThese metadata additions enable several useful operations:\n\n1. List all Secrets managed by tokenaut:\n\t ```\n\t kubectl get secrets -l app.kubernetes.io/managed-by=tokenaut\n\t ```\n\n2. Find the Secret associated with a specific InstallationAccessToken:\n\t ```\n\t kubectl get secrets -l tokenaut.appthrust.io/installation-access-token=\u003cnamespace\u003e.\u003cname\u003e\n\t ```\n\n3. View detailed information about a Secret, including its associated GitHub App and InstallationAccessToken:\n\t ```\n\t kubectl describe secret \u003csecret-name\u003e\n\t ```\n\n4. Find all Secrets associated with a specific GitHub App:\n\t ```\n\t kubectl get secrets -o json | jq '.items[] | select(.metadata.annotations.\"tokenaut.appthrust.io/app-id\"==\"\u003capp-id\u003e\")'\n\t ```\n\n5. Find all Secrets from a specific namespace's InstallationAccessTokens:\n\t ```\n\t kubectl get secrets -o json | jq '.items[] | select(.metadata.annotations.\"tokenaut.appthrust.io/source-namespace\"==\"\u003cnamespace\u003e\")'\n\t ```\n\nThese metadata additions make it easier for operators to manage and track the Secrets created by tokenaut, enhancing the overall observability and maintainability of the system.\n\n## Best Practices\n\n### Annotating the GitHub App Private Key Secret\n\nWhen creating the `github-app-private-key` Secret, it's beneficial to include additional metadata as annotations. While the `privateKey` field is the only required data, adding extra information can greatly improve key management and traceability. Consider including the following annotations:\n\n- `sha256`: The SHA256 fingerprint of the private key\n- `created-at`: The creation date of the private key\n- `github-app-url`: The URL of the GitHub App\n\nHere's an example of how to create the Secret with these annotations:\n\n```diff\n apiVersion: v1\n kind: Secret\n metadata:\n   name: github-app-private-key\n   namespace: default\n+  annotations:\n+    example.com/sha256: 6Bh3506/pnTDWJ/YxCU22p5RZgx7NDvoPfy7UMEXsJ8=\n+    example.com/created-at: 2024-04-01T12:00:00Z\n+    example.com/github-app-url: https://github.com/organizations/your-org/settings/apps/your-app-slug\n type: tokenaut.appthrust.io/private-key\n stringData:\n   privateKey: |\n     -----BEGIN RSA PRIVATE KEY-----\n     ...\n     -----END RSA PRIVATE KEY-----\n```\n\nBenefits of this approach:\n\n1. **Easy Identification**: The SHA256 fingerprint is displayed in the GitHub UI, making it easy to match the Secret with the correct key in your GitHub App settings.\n2. **Auditing**: The creation date helps track when the key was generated, useful for key rotation policies and auditing.\n3. **Simplified Maintenance**: These annotations make it easier to manage multiple keys or troubleshoot issues related to key expiration or mismatch.\n4. **Clear Association**: The GitHub App URL provides a direct link to the associated app, eliminating any ambiguity about which app the key belongs to.\n\nBy following this practice, you can significantly improve the manageability and traceability of your GitHub App private keys within your Kubernetes cluster. The added GitHub App URL annotation ensures that you can quickly navigate to the correct app settings, which is particularly helpful when managing multiple GitHub Apps or in large organizations.\n\n## Troubleshooting\n\n### Error: \"Failed to create token: unexpected status code: 401: A JSON web token could not be decoded\"\n\nIf you encounter this error, it typically means that the GitHub App's private key is incorrect, and GitHub is rejecting the attempt to issue a token with an invalid JWT.\n\nTo resolve this issue:\n\n1. Verify that the GitHub App's private key is correctly stored in the Secret resource.\n2. Double-check that you've copied the entire private key, including the `-----BEGIN RSA PRIVATE KEY-----` and `-----END RSA PRIVATE KEY-----` lines.\n3. If the problem persists, try regenerating a new private key for your GitHub App and update the Secret accordingly.\n\nRemember to always keep your private key secure and never expose it in your code or version control systems.\n\n## Development Guide\n\n### Publishing the tokenaut Image to Quay.io\n\n#### Prerequisites\n- Docker is installed\n- Docker Buildx is enabled\n- You have a Quay.io account\n\n#### Important Notes\n- The `tokenaut` repository on Quay.io is public.\n- Currently, the build and push process is not automated. Follow these steps to build and push locally.\n\n#### Steps\n\n1. Log in to Quay.io\n\t ```\n\t docker login quay.io\n\t ```\n\t Enter your Quay.io username and password when prompted.\n\n2. Build multi-architecture image\n\t ```\n\t make docker-buildx IMG=quay.io/appthrust/tokenaut:\u003cversion\u003e\n\t ```\n\t Example: `make docker-buildx IMG=quay.io/appthrust/tokenaut:v0.1.0`\n\n\t This command builds images for both ARM64 and AMD64 architectures.\n\n3. Verify the image\n\t ```\n\t docker buildx imagetools inspect quay.io/appthrust/tokenaut:\u003cversion\u003e\n\t ```\n\t Example: `docker buildx imagetools inspect quay.io/appthrust/tokenaut:v0.1.0`\n\n\t This command checks the manifest and supported architectures of the built image.\n\n4. Push the image\n\t ```\n\t make docker-push IMG=quay.io/appthrust/tokenaut:\u003cversion\u003e\n\t ```\n\t Example: `make docker-push IMG=quay.io/appthrust/tokenaut:v0.1.0`\n\n\t This command pushes the multi-architecture image to Quay.io.\n\n5. Update the latest tag\n\t ```\n\t docker tag quay.io/appthrust/tokenaut:\u003cversion\u003e quay.io/appthrust/tokenaut:latest\n\t docker push quay.io/appthrust/tokenaut:latest\n\t ```\n\t Example:\n\t ```\n\t docker tag quay.io/appthrust/tokenaut:v0.1.0 quay.io/appthrust/tokenaut:latest\n\t docker push quay.io/appthrust/tokenaut:latest\n\t ```\n\n\t This updates the `latest` tag to point to the new version.\n\n6. Verify on Quay.io web interface\n\t Log in to the Quay.io website and check the `appthrust/tokenaut` repository. Confirm that the newly pushed tags (specified version and latest) are displayed.\n\n### Helm Chart Release Process\n\nThis guide outlines the steps to release the tokenaut Helm chart to quay.io.\n\n**Important Note:**\nIdeally, the Helm Chart release process should be automated. However, as of now, the automation is not yet in place. Therefore, developers need to follow this manual process on their local environment. In the future, we aim to integrate this process into our CI/CD pipeline for automation.\n\n#### Prerequisites\n\n- Access to the appthrust organization on quay.io\n\n#### Release Steps\n\n1. **Update Version**\n\t Open the `chart/Chart.yaml` file and update the `version` field:\n\t ```yaml\n\t version: X.Y.Z  # Update to the new version number\n\t ```\n\t Also update the `appVersion` if necessary.\n\n2. **Package the Chart**\n\t ```bash\n\t helm package ./chart\n\t ```\n\t This will generate a `tokenaut-X.Y.Z.tgz` file.\n\n3. **Login to quay.io**\n\t ```bash\n\t helm registry login quay.io\n\t ```\n\t Enter your quay.io credentials when prompted.\n\n4. **Push the Chart**\n\t ```bash\n\t helm push tokenaut-X.Y.Z.tgz oci://quay.io/appthrust/tokenaut-helm\n\t ```\n\n5. **Verify the Push**\n\t Check the tokenaut-helm repository in the appthrust organization on quay.io to ensure the new version was pushed correctly.\n\n6. **Test Installation**\n\t Install the newly released chart in a test environment to verify it functions correctly:\n\t ```bash\n\t helm install test-tokenaut oci://quay.io/appthrust/tokenaut-helm/tokenaut --version X.Y.Z\n\t ```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fappthrust%2Ftokenaut","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fappthrust%2Ftokenaut","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fappthrust%2Ftokenaut/lists"}