github.com/argoproj/argo-cd/v3@v3.2.1/docs/proposals/manifest-hydrator.md (about)

     1  ---
     2  title: Manifest Hydrator
     3  authors:
     4    - "@crenshaw-dev"
     5    - "@zachaller"
     6  sponsors:
     7    - TBD        # List all interested parties here.
     8  reviewers:
     9    - TBD
    10  approvers:
    11    - TBD
    12  
    13  creation-date: 2024-03-26
    14  last-updated: 2024-03-26
    15  ---
    16  
    17  # Manifest Hydrator
    18  
    19  This proposal describes a feature to make manifest hydration (i.e. the "rendered manifest pattern") a first-class feature of Argo CD.
    20  
    21  ## Terms
    22  
    23  * dry manifests: DRY or Don't Repeat Yourself - things like Kustomize overlays and Helm charts that produce Kubernetes manifests but are not themselves Kubernetes Manifests
    24  * hydrated manifests: the output from dry manifest tools, i.e. plain Kubernetes manifests
    25  
    26  ## Summary
    27  
    28  Manifest hydration tools like Helm and Kustomize are indispensable in GitOps. These tools transform "dry" (Don't Repeat Yourself) sources into plain Kubernetes manifests. The effects of a change to dry sources are not always obvious. So storing only dry sources in git leaves the user with an incomplete and confusing history of their application. This undercuts some of the main benefits of GitOps.
    29  
    30  The "rendered manifests" pattern has emerged as a way to mitigate the downsides of using hydration tools in GitOps. Today, developers use CI tools to automatically hydrate manifests and push to separate branches. They then configure Argo CD to deploy from the hydrated branches. (For more information, see the awesome [blog post](https://akuity.io/blog/the-rendered-manifests-pattern/) and [ArgoCon talk](https://www.youtube.com/watch?v=TonN-369Qfo) by Nicholas Morey.)
    31  
    32  This proposal describes manifest hydration and pushing to git as a first-class feature of Argo CD.
    33  
    34  It offers two modes of operation: push-to-deploy and push-to-stage. In push-to-deploy, hydrated manifests are pushed to the same branch from which Argo CD deploys. In push-to-stage, manifests are pushed to a different branch, and Argo CD relies on some external system to move changes to the deployment branch; this provides an integration point for automated environment promotion systems.
    35  
    36  ### Opinions
    37  
    38  This proposal is opinionated. It is based on the belief that, in order to reap the full benefits of GitOps, every change to an application's desired state must originate from a commit to a single GitOps repository. In other words, the full history of the application's desired state must be visible as the commit history on a git repository.
    39  
    40  This requirement is incompatible with tooling which injects nondeterministic configuration into the desired state before it is deployed by the GitOps controller. Examples of nondeterministic external configuration are:
    41  
    42  1) Helm chart dependencies on unpinned chart versions
    43  2) Kustomize remote bases to unpinned git revisions
    44  3) Config tool parameter overrides in the Argo CD Application `spec.source` fields
    45  4) Multiple sources referenced in the same application (knowledge of combination of source versions is held externally to git)
    46  
    47  Injecting nondeterministic configuration makes it impossible to know the complete history of an application by looking at a git branch history. Even if the nondeterministic output is databased (for example, in a hydrated source branch in git), it is impossible for developers to confidently make changes to desired state, because they cannot know ahead of time what other configuration will be injected at deploy time.
    48  
    49  We believe that the problems of injecting external configuration are best solved by asking these two questions:
    50  
    51  1) Does the configuration belong in the developer's interface (i.e. the dry manifests)?
    52  2) Does the configuration need to be mutable at runtime, or only at deploy time?
    53  
    54  If the configuration belongs in the developer's interface, write a tool to push the information to git. Image tags are a good example of such configuration, and the Argo CD Image Updater is a good example of such tooling.
    55  
    56  If the configuration doesn't belong in the developer's interface, and it needs to be updated at runtime, write a controller. The developer shouldn't be expected to maintain configuration which is not an immediate part of their desired state. An example would be an auto-sizing controller which eliminates the need for the developer to manage their own autoscaler config.
    57  
    58  If the configuration doesn't belong in the developer's interface and doesn't need to be updated at runtime (only at deploy time), write a mutating webhook. This is a great option for injecting cluster-specific configuration that the developer doesn't need to directly control.
    59  
    60  With these three options available (git-pushers, controllers, and mutating webhooks), we believe that it is not generally necessary to inject nondeterministic configuration into the manifest hydration process. Instead, we can have a full history of the developer's minimal intent (dry branch) and the full expression of that intent (hydrated branch) completely recorded in a series of commits on a git branch.
    61  
    62  By respecting these limitations, we unlock the ability to manage change promotion/reversion entirely via git. Change lineage is fully represented as a series of dry commit hashes. This makes it possible to write reliable rules around how these hashes are promoted to different environments and how they are reverted (i.e. we can meaningfully say "`prod` may never be more than one dry hash ahead of `test`"). If information about the lineage of an application is scattered among multiple sources, it is difficult or even impossible to meaningfully define rules about how one environment's lineage must relate to that of another environment.
    63  
    64  Being opinionated unlocks the full benefits of GitOps as well as the ability to build a reasonable, reliable preview/promotion/reversion system. 
    65  
    66  These opinions will lock out use cases where configuration injection cannot be avoided by writing git-pushers, controllers, or mutating webhooks. We believe that the benefits of making an opinionated system outweigh the costs of compromising those opinions.
    67  
    68  ## Motivation
    69  
    70  Many organizations have implemented their own manifest hydration system. By implementing it in Argo CD, we can lower the cost to our users of maintaining those systems, and we can encourage best practices related to the pattern.
    71  
    72  ### Goals
    73  
    74  1) Make manifest hydration easy and intuitive for Argo CD users
    75  2) Make it possible to implement a promotion system which relies on the manifest hydration's push-to-stage mode
    76  3) Emphasize maintaining as much of the system's state as possible in git rather than in the Application CR (e.g. source hydrator config values, such as Helm values)
    77  4) Every deployed change must have a corresponding dry commit - i.e. git is always the source of any changes
    78  5) Developers should be able to easily reproduce the manifest hydration process locally, i.e. by running some commands
    79  
    80  #### Hydration Reproducibility
    81  
    82  One goal of this proposal is to make hydration reproducibility easy. Reproducibility brings a couple benefits: easy iteration/debugging and reliable previews.
    83  
    84  ##### Easy Iteration/Debugging
    85  
    86  The hydration system should enable developers to easily reproduce the hydration process locally. The developer should be able to run a short series of commands and perform the exact same tasks that Argo CD would take to hydrate their manifests. This allows the developer to verify that Argo CD is behaving as expected and to quickly tweak inputs and see the results. This lets them iterate quickly and improves developer satisfaction and change velocity.
    87  
    88  To provide this experience, the hydrator needs to provide the developer with a few pieces of information:
    89  
    90  1) The input repo URL, path, and commit SHA
    91  2) The hydration tool CLI version(s) (for example, the version of the Helm CLI used for hydration)
    92  3) A series of commands and arguments which the developer can run locally
    93  
    94  Equipped with this information, the developer can perform the exact same steps as Argo CD and be confident that their dry manifest changes will produce the desired output.
    95  
    96  Ensuring that hydration is deterministic assures the developer that the output for a given dry state will be the same next week as it is today.
    97  
    98  ###### Avoiding Esoteric Behavior
    99  
   100  We should avoid the developer needing to know Argo CD-specific behavior in order to reproduce hydration. Tools like Helm, Kustimize, etc. have excellent public-facing documentation which the developer should be able to take advantage of without needing to know quirks of Argo CD.
   101  
   102  ##### Reliable Previews
   103  
   104  Deterministic hydration output allows Argo CD to produce a reliable change preview when a developer proposes a change to the dry manifests via a PR.
   105  
   106  If output is not deterministic, then a preview generated today might not be valid/correct a week, day, or even hour later. Non-determinism makes it so that developers can't trust that the change they review will be the change actually applied.
   107  
   108  ### Non-Goals
   109  
   110  1) Implementing a change promotion system
   111  
   112  ## Open Questions
   113  
   114  * The `sourceHydrator` field is mutually exclusive with the `source` and the `sources` field. Should we throw an error if they're both configured, or should we just pick one and ignore the others?
   115  * How will/should this feature relate to the image updater? Is there an opportunity to share code, since both tools involve pushing to git?
   116  * Should we enforce a naming convention for hydrated manifest branches, e.g. `argo/...`? This would make it easier to recommend branch protection rules, for example, only allow pushes to `argo/*` from the argo bot.
   117  * Should we enforce setting a `sourceHydrator.syncSource.path` to something besides `.`? Setting a path makes it easier to add/remove other apps later if desired.
   118  
   119  ## Proposal
   120  
   121  Today, Argo CD watches one or more git repositories (configured in the `spec.source` or `spec.sources` field). When a new commit appears, Argo CD updates the desired state by rendering the manifests with the configured manifest hydration tool. If auto-sync is enabled, Argo CD applies the new manifests to the cluster.
   122  
   123  With the introduction of this change, Argo CD will watch two revisions in the same git repository: the first is the "dry source", i.e. the git repo/revision where the un-rendered manifests reside, and the second is the "hydrated source," where the rendered manifests are places and retrieved for syncing to the cluster.
   124  
   125  ### New `spec.sourceHydrator` Application Field
   126  
   127  A `sourceHydrator` field will be added to the Argo CD Application spec:
   128  
   129  ```yaml
   130  apiVersion: argoproj.io/v1alpha1
   131  kind: Application
   132  metadata:
   133    name: example
   134  spec:
   135    # The sourceHydrator field is mutually-exclusive with `source` and with `sources`. If this field is configured, we 
   136    # should either throw an error or ignore the other two.
   137    sourceHydrator:
   138      drySource:
   139        repoURL: https://github.com/argoproj/argocd-example-apps
   140        targetRevision: main
   141        # This assumes the Application's environments are modeled as directories.
   142        path: environments/e2e
   143      syncSource:
   144        targetBranch: environments/e2e
   145        path: .
   146      # The hydrateTo field is optional. If specified, Argo CD will write hydrated manifests to this branch instead of the
   147      # syncSource.targetBranch. This allows the user to "stage" a hydrated commit before actually deploying the changes
   148      # by merging them into the syncSource branch. A complete change promotion system can be built around this feature. 
   149      hydrateTo:
   150        targetBranch: environments/e2e-next
   151        # The path is assumed to be the same as that in syncSource.
   152  ```
   153  
   154  When the Argo CD application controller detects a new commit on the `drySource`, it queue up the hydration process.
   155  
   156  When the application controller detects a new (hydrated) commit on the `syncSource.targetBranch`, it will sync the manifests.
   157  
   158  ### Processing a New Dry Commit
   159  
   160  On noticing a new dry commit, Argo CD will first collect all Applications which have the same `drySource` repo and targetRevision.
   161  
   162  Argo CD will then group those sources by the configured `syncSource` targetBranch.
   163  
   164  ```go
   165  package hydrator
   166  
   167  import "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
   168  
   169  type DrySource struct {
   170  	repoURL        string
   171  	targetRevision string
   172  }
   173  
   174  type SyncSource struct {
   175  	targetBranch string
   176  }
   177  
   178  var appGroups map[DrySource]map[SyncSource][]v1alpha1.Application
   179  ```
   180  
   181  Then Argo CD will loop over the apps in each group. For each group, it will run manifest hydration on the configured `drySource.path` and write the result to the configured `syncSource.path`. After looping over all apps in the group and writing all their manifests, it will commit the changes to the configured `syncSource` repoURL and targetBranch (or, if configured, the `hydratedTo` targetBranch). Finally, it will push those changes to git. Then it will repeat this process for the remaining groups.
   182  
   183  The actual push operation should be delegated to the [commit server](./manifest-hydrator/commit-server/README.md).
   184  
   185  To understand how this would work for a simple dev/test/prod setup with two regions, consider this example:
   186  
   187  ```yaml
   188  ### DEV APPS ###
   189  apiVersion: argoproj.io/v1alpha1
   190  kind: Application
   191  metadata:
   192    name: dev-west
   193  spec:
   194    sourceHydrator:
   195      drySource:
   196        repoURL: https://github.com/argoproj/argocd-example-apps
   197        targetRevision: main
   198        path: environments/dev/west
   199      syncSource:
   200        targetBranch: environments/dev
   201        path: west
   202  ---
   203  apiVersion: argoproj.io/v1alpha1
   204  kind: Application
   205  metadata:
   206    name: dev-east
   207  spec:
   208    sourceHydrator:
   209      drySource:
   210        repoURL: https://github.com/argoproj/argocd-example-apps
   211        targetRevision: main
   212        path: environments/dev/east
   213      syncSource:
   214        targetBranch: environments/dev
   215        path: east
   216  ---
   217  ### TEST APPS ###
   218  apiVersion: argoproj.io/v1alpha1
   219  kind: Application
   220  metadata:
   221    name: test-west
   222  spec:
   223    sourceHydrator:
   224      drySource:
   225        repoURL: https://github.com/argoproj/argocd-example-apps
   226        targetRevision: main
   227        path: environments/test/west
   228      syncSource:
   229        targetBranch: environments/test
   230        path: west
   231  ---
   232  apiVersion: argoproj.io/v1alpha1
   233  kind: Application
   234  metadata:
   235    name: test-east
   236  spec:
   237    sourceHydrator:
   238      drySource:
   239        repoURL: https://github.com/argoproj/argocd-example-apps
   240        targetRevision: main
   241        path: environments/test/east
   242      syncSource:
   243        targetBranch: environments/prod
   244        path: east
   245  ---
   246  ### PROD APPS ###
   247  apiVersion: argoproj.io/v1alpha1
   248  kind: Application
   249  metadata:
   250    name: prod-west
   251  spec:
   252    sourceHydrator:
   253      drySource:
   254        repoURL: https://github.com/argoproj/argocd-example-apps
   255        targetRevision: main
   256        path: environments/prod/west
   257      syncSource:
   258        targetBranch: environments/prod
   259        path: west
   260  ---
   261  apiVersion: argoproj.io/v1alpha1
   262  kind: Application
   263  metadata:
   264    name: prod-east
   265  spec:
   266    sourceHydrator:
   267      drySource:
   268        repoURL: https://github.com/argoproj/argocd-example-apps
   269        targetRevision: main
   270        path: environments/prod/east
   271      syncSource:
   272        targetBranch: environments/prod
   273        path: east
   274  ---
   275  ```
   276  
   277  Each commit to the dry branch will result in a commit to up to three branches. Each commit to an environment branch will contain changes for west, east, or both (depending on which is affected). Changes originating from a single dry commit are always grouped into a single hydrated commit.
   278  
   279  ### Handling External Values Files
   280  
   281  Since only one source may be used in as the dry source, the multi-source approach to external Helm values files will not work here. Instead, we'll recommend that users use the umbrella chart approach. The main reasons for multi-source as an alternative were convenience (no need to maintain the parent chart) and resolving issues with authentication to dependency charts. We believe the simplification is worth the cost of convenience, and we can address the auth issues as standalone bugs.
   282  
   283  An earlier iteration of this proposal attempted to preserve the multi-source style of external value file inclusion by introducing a "magic" `.argocd-hydrator.yaml` file containing `additionalSources` to reference the Helm chart. In the end, it felt like we were re-implementing Helm's dependencies feature or git submodules. It's better to just rely on one of those existing tools.
   284  
   285  ### `.argocd-source.yaml` Support
   286  
   287  The `spec.sourceHydrator.drySource` field contains only three fields: `repoURL`, `targetRevision`, and `path`.
   288  
   289  `spec.source` contains a number of fields for configuring manifest hydration tools (`helm`, `kustomize`, and `directory`). That functionality is still available for `spec.sourceHydrator`. But instead of being configured in the Application CR, those values are set in `.argocd-source.yaml`, an existing "override" mechanism for `spec.source`. By requiring that this configuration be set in `.argocd-source.yaml`, we respect the principle that all changes must be made in git instead of in the Application CR.
   290  
   291  ### `spec.destination.namespace` Behavior
   292  
   293  The Application `spec.destination.namespace` field is used to set the `metadata.namespace` field of any namespace resources for which that field is not set in the manifests.
   294  
   295  The hydrator will not inject `metadata.namespace` into the hydrated manifests pushed to git. Instead, Argo CD's behavior of injecting that value immediately before applying to the cluster will continue to be used with the `spec.sourceHydrator.syncSource`.
   296  
   297  ### Build Environment Support
   298  
   299  For sources specified in `spec.source` or `spec.sources`, Argo CD [sets certain environment variables](https://argo-cd.readthedocs.io/en/stable/user-guide/build-environment/) before running the manifest hydration tool.
   300  
   301  Some of these environment variables may change independently of the dry source and therefore break the reproducibility of manifest hydration (see the [Opinions](#opinions) section). Therefore, only some environment variables will be populated for the `spec.sourceHydrator` source.
   302  
   303  These environment variables will **not** be set:
   304  
   305  * `ARGOCD_APP_NAME`
   306  * `ARGOCD_APP_NAMESPACE`
   307  * `KUBE_VERSION`
   308  * `KUBE_API_VERSIONS`
   309  
   310  These environment variables will be set because they are commit SHAs and are directly and immutably tied to the dry manifest commit:
   311  
   312  * `ARGOCD_APP_REVISION`
   313  * `ARGOCD_APP_REVISION_SHORT`
   314  
   315  These environment variables will be set because they are inherently tied to the manifest hydrator configuration. If these fields set in `spec.sourceHydrator.drySource` change, we are breaking the connection to the original hydrator configuration anyway.
   316  
   317  * `ARGOCD_APP_SOURCE_PATH`
   318  * `ARGOCD_APP_SOURCE_REPO_URL`
   319  * `ARGOCD_APP_SOURCE_TARGET_REVISION`
   320  
   321  ### Support for Helm-Specific Features
   322  
   323  #### App Name / Release Name
   324  
   325  By default, Argo CD's `source` and `sources` fields use the Application's name as the release name when hydrating Helm manifests.
   326  
   327  To centralize the source of truth when using `spec.sourceHydrator`, the default release name will be an empty string, and any different release name should be specified in the `helm.releaseName` field in `.argocd-source.yaml`.
   328  
   329  #### Kube API Versions
   330  
   331  `helm install` supports dynamically reading Kube API versions from the destination cluster to adjust manifest output. `helm template` accepts a list of Kube API versions to simulate the same behavior, and Argo CD's `spec.source` and `spec.sources` fields set those API versions when running `helm template`.
   332  
   333  To centralize the source of truth when using `spec.sourceHydrator`, the Kube API versions will not be populated by default.
   334  
   335  Instead, a new field will be added to the Application's `spec.source.helm` field:
   336  
   337  ```yaml
   338  kind: Application
   339  spec:
   340    source:
   341      helm:
   342        apiVersions:
   343          - admissionregistration.k8s.io/v1/MutatingWebhookConfiguration
   344          - admissionregistration.k8s.io/v1/ValidatingWebhookConfiguration
   345          - ... etc.
   346  ```
   347  
   348  That field will also be available in `.argocd-source.yaml`:
   349  
   350  ```yaml
   351  helm:
   352    apiVersions:
   353      - admissionregistration.k8s.io/v1/MutatingWebhookConfiguration
   354      - admissionregistration.k8s.io/v1/ValidatingWebhookConfiguration
   355      - ... etc.
   356  ```
   357  
   358  So the appropriate way to set Kube API versions for the source hydrator will be to populate the `.argocd-source.yaml` file.
   359  
   360  #### Hydrated Environment Branches
   361  
   362  Representing the dry manifests of environments as branches has well-documented downsides for developer experience. Specifically, it's toilsome for developers to manage moving changes from one branch to another and avoid drift.
   363  
   364  So environments-as-directories has emerged as the standard for good GitOps practices. Change management across directories in a single branch is much easier to perform and reason about.
   365  
   366  **This proposal does not suggest using branches to represent the dry manifests of environments.** As a matter of fact, this proposal codifies the current best practice of representing the dry manifests as directories in a single branch.
   367  
   368  This proposal recommends using different branches for the _hydrated_ representation of environments only. Using different branches has some benefits:
   369  
   370  1) Intuitive grouping of "changes to ship at once" - for example, if you have app-1-east and app-1-west, it makes sense to merge a single hydrated PR to deploy to both of those apps at once
   371  2) Easy-to-read history of a single environment via the commits history
   372  3) Easy comparison between environments using the SCMs' "compare" interfaces
   373  
   374  In other words, branches make a very nice _read_ interface for _hydrated_ manifests while preserving the best-practice of using _directories_ for the _write_ interface.
   375  
   376  ### Commit Metadata
   377  
   378  Each output directory should contain two files: manifest.yaml and README.md. manifest.yaml should contain the plain hydrated manifests. The resources should be sorted by namespace, name, group, and kind (in that order).
   379  
   380  The README will be built using the following template:
   381  
   382  ````gotemplate
   383  {{ if eq (len .applications) 1 }}
   384  {{ $appName := (index .applications 0).metadata.name }}
   385  # {{ $appName }} Manifests
   386  
   387  [manifest.yaml](./manifest.yaml) contains the hydrated manifests for the {{ $appName }} application.
   388  {{ end }}
   389  {{ if gt (len .applications) 1 }}
   390  {{ $appName := (index .applications 0).metadata.name }}
   391  # Manifests for {{ len .applications }} Applications
   392  
   393  [manifest.yaml](./manifest.yaml) contains the hydrated manifests for these applications:
   394  {{ range $i, $app := .applications }}
   395  - {{ $app.name }}
   396  {{ end }}
   397  {{ end }}
   398  
   399  These are the details of the most recent change;
   400  * Author: {{ .commitAuthor }}
   401  * Message: {{ .commitMessage }}
   402  * Time: {{ .commitTime }}
   403  
   404  To reproduce the manifest hydration, do the following:
   405  
   406  ```
   407  git clone {{ .repoURL }}
   408  cd {{ .repoName }}
   409  git checkout {{ .dryShortSHA }}
   410  {{ range $i, $command := .commands }}
   411  {{ $command }}
   412  {{ end }}
   413  ```
   414  ````
   415  
   416  This template should be admin-configurable.
   417  
   418  Example output might look like this:
   419  
   420  ````markdown
   421  # dev-west Manifests
   422  
   423  [manifest.yaml](./manifest.yaml) contains the hydrated manifests for the dev-west application.
   424  
   425  These are the details of the most recent change;
   426  * Author: Michael Crenshaw <michael@example.com>
   427  * Message: chore: bumped image tag to v0.0.2
   428  * Time: 2024-03-27 10:32:04 UTC
   429  
   430  To reproduce the manifest hydration, do the following:
   431  
   432  ```
   433  git clone https://github.com/argoproj/argocd-example-apps
   434  cd argocd-example-apps
   435  git checkout ab2382f
   436  kustomize edit set image my-app:v0.0.2
   437  kustomize build environments/dev/west
   438  ```
   439  ````
   440  
   441  The hydrator will also write a `hydrator.metadata` file containing a JSON representation of all the values available for README templating. This metadata can be used by external systems (e.g. a PR-based promoter system) to generate contextual information about the hydrated manifest's provenance.
   442  
   443  ```json
   444  {
   445    "commands": ["kustomize edit set image my-app:v0.0.2", "kustomize build ."],
   446    "drySHA": "ab2382f",
   447    "commitAuthor": "Michael Crenshaw <michael@example.com>",
   448    "commitMessage": "chore: bump Helm dependency chart to 32.1.12",
   449    "repoURL": "https://github.com/argoproj/argocd-example-apps"
   450  }
   451  ```
   452  
   453  To request a commit to the hydrated branch, the application controller will make a call to the CommitManifests service.
   454  
   455  A single call will bundle all the changes destined for a given targetBranch.
   456  
   457  It's the application controller's job to ensure that the user has write access to the repo before making the call.
   458  
   459  ```protobuf
   460  // CommitManifests represents the caller's request for some Kubernetes manifests to be pushed to a git repository.
   461  message CommitManifests {
   462    // repoURL is the URL of the repo we're pushing to. HTTPS or SSH URLs are acceptable.
   463    required string repoURL = 1;
   464    // targetBranch is the name of the branch we're pushing to.
   465    required string targetBranch = 2;
   466    // drySHA is the full SHA256 hash of the "dry commit" from which the manifests were hydrated.
   467    required string drySHA = 3;
   468    // commitAuthor is the name of the author of the dry commit.
   469    required string commitAuthor = 4;
   470    // commitMessage is the short commit message from the dry commit.
   471    required string commitMessage = 5;
   472    // commitTime is the dry commit timestamp.
   473    required string commitTime = 6;
   474    // details holds the information about the actual hydrated manifests.
   475    repeated CommitPathDetails details = 7;
   476  }
   477  
   478  // CommitManifestDetails represents the details about a 
   479  message CommitPathDetails {
   480    // path is the path to the directory to which these manifests should be written.
   481    required string path = 1;
   482    // manifests is a list of JSON documents representing the Kubernetes manifests.
   483    repeated string manifests = 2;
   484    // readme is a string which will be written to a README.md alongside the manifest.yaml. 
   485    required string readme = 3;
   486  }
   487  
   488  message CommitManifestsResponse {
   489  }
   490  ```
   491  
   492  ### Push access
   493  
   494  The hydrator will need to push to the git repository. This will require a secret containing the git credentials.
   495  
   496  Write access will be configured via a Kubernetes secret with the following structure:
   497  
   498  ```yaml
   499  apiVersion: v1
   500  kind: Secret
   501  metadata:
   502    labels:
   503      argocd.argoproj.io/secret-type: repository-write
   504  stringData:
   505    url: 'https://github.com/argoproj/argocd-example-apps'
   506    githubAppID: '123456'
   507    githubInstallationID: '123456'
   508    githubAppPrivateKey: |
   509      -----
   510  ```
   511  
   512  ### Use cases
   513  
   514  #### Use case 1:
   515  
   516  An organization with strong requirements around change auditing might enable manifest hydration in order to generate a full history of changes.
   517  
   518  #### Use case 2:
   519  
   520  ### Implementation Details/Notes/Constraints
   521  
   522  ### Detailed examples
   523  
   524  ### Security Considerations
   525  
   526  This proposal would involve introducing a component capable of pushing to git.
   527  
   528  We'll need to consider what git permissions setup to recommend, what security features we should recommend enabling (e.g. branch protection), etc.
   529  
   530  We'll also need to consider how to store the git push secrets. It's probable that they'll need to be stored in a namespace separate from the other Argo CD components to provide a bit extra protection.
   531  
   532  ### Risks and Mitigations
   533  
   534  ### Upgrade / Downgrade Strategy
   535  
   536  ## Drawbacks
   537  
   538  ## Alternatives