diff --git a/.agents/skills/gitops-cluster-debug/SKILL.md b/.agents/skills/gitops-cluster-debug/SKILL.md index 42213e897..4b33d3702 100644 --- a/.agents/skills/gitops-cluster-debug/SKILL.md +++ b/.agents/skills/gitops-cluster-debug/SKILL.md @@ -5,9 +5,9 @@ description: | license: Apache-2.0 metadata: github-path: skills/gitops-cluster-debug - github-ref: refs/tags/v0.0.3 + github-ref: refs/tags/v0.0.4 github-repo: https://github.com/fluxcd/agent-skills - github-tree-sha: f1463d4de7168c3561f680a2613c3b68578f09ca + github-tree-sha: 434d303add349e64129103242e7ec7d58d60f8a1 name: gitops-cluster-debug --- # Flux Cluster Debugger diff --git a/.agents/skills/gitops-cluster-debug/assets/schemas/fluxinstance-fluxcd-v1.json b/.agents/skills/gitops-cluster-debug/assets/schemas/fluxinstance-fluxcd-v1.json index 1f6e9a51d..1635135e4 100644 --- a/.agents/skills/gitops-cluster-debug/assets/schemas/fluxinstance-fluxcd-v1.json +++ b/.agents/skills/gitops-cluster-debug/assets/schemas/fluxinstance-fluxcd-v1.json @@ -13,9 +13,11 @@ "type": "object" }, "spec": { + "additionalProperties": false, "description": "FluxInstanceSpec defines the desired state of FluxInstance", "properties": { "cluster": { + "additionalProperties": false, "description": "Cluster holds the specification of the Kubernetes cluster.", "properties": { "domain": { @@ -82,10 +84,10 @@ "message": ".objectLevelWorkloadIdentity must be set to true when .multitenantWorkloadIdentity is set to true", "rule": "(has(self.objectLevelWorkloadIdentity) && self.objectLevelWorkloadIdentity) || !has(self.multitenantWorkloadIdentity) || !self.multitenantWorkloadIdentity" } - ], - "additionalProperties": false + ] }, "commonMetadata": { + "additionalProperties": false, "description": "CommonMetadata specifies the common labels and annotations that are\napplied to all resources. Any existing label or annotation will be\noverridden if its key matches a common one.", "properties": { "annotations": { @@ -103,8 +105,7 @@ "type": "object" } }, - "type": "object", - "additionalProperties": false + "type": "object" }, "components": { "description": "Components is the list of controllers to install.\nDefaults to the core Flux controllers:\n - source-controller\n - kustomize-controller\n - helm-controller\n - notification-controller", @@ -124,6 +125,7 @@ "type": "array" }, "distribution": { + "additionalProperties": false, "description": "Distribution specifies the version and container registry to pull images from.", "properties": { "artifact": { @@ -162,15 +164,16 @@ "registry", "version" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "kustomize": { + "additionalProperties": false, "description": "Kustomize holds a set of patches that can be applied to the\nFlux installation, to customize the way Flux operates.", "properties": { "patches": { "description": "Strategic merge and JSON patches, defined as inline YAML objects,\ncapable of targeting objects based on kind, label and annotation selectors.", "items": { + "additionalProperties": false, "description": "Patch contains an inline StrategicMerge or JSON6902 patch, and the target the patch should\nbe applied to.", "properties": { "patch": { @@ -178,6 +181,7 @@ "type": "string" }, "target": { + "additionalProperties": false, "description": "Target points to the resources that the patch document should be applied to.", "properties": { "annotationSelector": { @@ -209,21 +213,18 @@ "type": "string" } }, - "type": "object", - "additionalProperties": false + "type": "object" } }, "required": [ "patch" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" } }, - "type": "object", - "additionalProperties": false + "type": "object" }, "migrateResources": { "default": true, @@ -231,6 +232,7 @@ "type": "boolean" }, "sharding": { + "additionalProperties": false, "description": "Sharding holds the specification of the sharding configuration.", "properties": { "key": { @@ -258,10 +260,10 @@ "required": [ "shards" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "storage": { + "additionalProperties": false, "description": "Storage holds the specification of the source-controller\npersistent volume claim.", "properties": { "class": { @@ -277,10 +279,10 @@ "class", "size" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "sync": { + "additionalProperties": false, "description": "Sync specifies the source for the cluster sync operation.\nWhen set, a Flux source (GitRepository, OCIRepository or Bucket)\nand Flux Kustomization are created to sync the cluster state\nwith the source repository.", "properties": { "interval": { @@ -314,7 +316,7 @@ "type": "string" }, "provider": { - "description": "Provider specifies OIDC provider for source authentication.\nFor OCIRepository and Bucket the provider can be set to 'aws', 'azure' or 'gcp'.\nfor GitRepository the accepted value can be set to 'azure' or 'github'.\nTo disable OIDC authentication the provider can be set to 'generic' or left empty.", + "description": "Provider specifies OIDC provider for source authentication.\nFor OCIRepository and Bucket the provider can be set to 'aws', 'azure' or 'gcp'.\nFor GitRepository the provider can be set to 'aws' (requires Flux 2.9 or later),\n'azure' or 'github'.\nTo disable OIDC authentication the provider can be set to 'generic' or left empty.", "enum": [ "generic", "aws", @@ -344,7 +346,16 @@ "url" ], "type": "object", - "additionalProperties": false + "x-kubernetes-validations": [ + { + "message": "sync.provider 'gcp' is only supported for OCIRepository and Bucket", + "rule": "!has(self.provider) || self.provider != 'gcp' || self.kind == 'OCIRepository' || self.kind == 'Bucket'" + }, + { + "message": "sync.provider 'github' is only supported for GitRepository", + "rule": "!has(self.provider) || self.provider != 'github' || self.kind == 'GitRepository'" + } + ] }, "wait": { "default": true, @@ -355,15 +366,16 @@ "required": [ "distribution" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "status": { + "additionalProperties": false, "description": "FluxInstanceStatus defines the observed state of FluxInstance", "properties": { "components": { "description": "Components contains the container images used by the components.", "items": { + "additionalProperties": false, "description": "ComponentImage represents a container image used by a component.", "properties": { "digest": { @@ -388,14 +400,14 @@ "repository", "tag" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" }, "conditions": { "description": "Conditions contains the readiness conditions of the object.", "items": { + "additionalProperties": false, "description": "Condition contains details for one aspect of the current state of this API Resource.", "properties": { "lastTransitionTime": { @@ -444,14 +456,14 @@ "status", "type" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" }, "history": { "description": "History contains the reconciliation history of the FluxInstance\nas a list of snapshots ordered by the last reconciled time.", "items": { + "additionalProperties": false, "description": "Snapshot represents a point-in-time record of a group of resources reconciliation,\nincluding timing information, status, and a unique digest identifier.", "properties": { "digest": { @@ -497,17 +509,18 @@ "lastReconciledStatus", "totalReconciliations" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" }, "inventory": { + "additionalProperties": false, "description": "Inventory contains a list of Kubernetes resource object references\nlast applied on the cluster.", "properties": { "entries": { "description": "Entries of Kubernetes resource object references.", "items": { + "additionalProperties": false, "description": "ResourceRef contains the information necessary to locate a resource within a cluster.", "properties": { "id": { @@ -523,8 +536,7 @@ "id", "v" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" } @@ -532,8 +544,7 @@ "required": [ "entries" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "lastAppliedRevision": { "description": "LastAppliedRevision is the version and digest of the\ndistribution config that was last reconcile.", @@ -556,8 +567,7 @@ "type": "string" } }, - "type": "object", - "additionalProperties": false + "type": "object" } }, "type": "object", @@ -567,4 +577,4 @@ "rule": "self.metadata.name == 'flux'" } ] -} \ No newline at end of file +} diff --git a/.agents/skills/gitops-cluster-debug/assets/schemas/fluxreport-fluxcd-v1.json b/.agents/skills/gitops-cluster-debug/assets/schemas/fluxreport-fluxcd-v1.json index a7f6fc861..e7b9876d4 100644 --- a/.agents/skills/gitops-cluster-debug/assets/schemas/fluxreport-fluxcd-v1.json +++ b/.agents/skills/gitops-cluster-debug/assets/schemas/fluxreport-fluxcd-v1.json @@ -13,9 +13,11 @@ "type": "object" }, "spec": { + "additionalProperties": false, "description": "FluxReportSpec defines the observed state of a Flux installation.", "properties": { "cluster": { + "additionalProperties": false, "description": "Cluster is the version information of the Kubernetes cluster.", "properties": { "nodes": { @@ -35,12 +37,12 @@ "platform", "serverVersion" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "components": { "description": "ComponentsStatus is the status of the Flux controller deployments.", "items": { + "additionalProperties": false, "description": "FluxComponentStatus defines the observed state of a Flux component.", "properties": { "image": { @@ -66,12 +68,12 @@ "ready", "status" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" }, "distribution": { + "additionalProperties": false, "description": "Distribution is the version information of the Flux installation.", "properties": { "entitlement": { @@ -95,10 +97,10 @@ "entitlement", "status" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "operator": { + "additionalProperties": false, "description": "Operator is the version information of the Flux Operator.", "properties": { "apiVersion": { @@ -119,12 +121,12 @@ "platform", "version" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "reconcilers": { "description": "ReconcilersStatus is the list of Flux reconcilers and\ntheir statistics grouped by API kind.", "items": { + "additionalProperties": false, "description": "FluxReconcilerStatus defines the observed state of a Flux reconciler.", "properties": { "apiVersion": { @@ -136,6 +138,7 @@ "type": "string" }, "stats": { + "additionalProperties": false, "description": "Stats is the reconcile statics of the Flux resource kind.", "properties": { "failing": { @@ -160,20 +163,19 @@ "running", "suspended" ], - "type": "object", - "additionalProperties": false + "type": "object" } }, "required": [ "apiVersion", "kind" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" }, "sync": { + "additionalProperties": false, "description": "SyncStatus is the status of the cluster sync\nSource and Kustomization resources.", "properties": { "id": { @@ -202,22 +204,22 @@ "ready", "status" ], - "type": "object", - "additionalProperties": false + "type": "object" } }, "required": [ "distribution" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "status": { + "additionalProperties": false, "description": "FluxReportStatus defines the readiness of a FluxReport.", "properties": { "conditions": { "description": "Conditions contains the readiness conditions of the object.", "items": { + "additionalProperties": false, "description": "Condition contains details for one aspect of the current state of this API Resource.", "properties": { "lastTransitionTime": { @@ -266,8 +268,7 @@ "status", "type" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" }, @@ -276,8 +277,7 @@ "type": "string" } }, - "type": "object", - "additionalProperties": false + "type": "object" } }, "type": "object", @@ -287,4 +287,4 @@ "rule": "self.metadata.name == 'flux'" } ] -} \ No newline at end of file +} diff --git a/.agents/skills/gitops-cluster-debug/assets/schemas/helmrelease-helm-v2.json b/.agents/skills/gitops-cluster-debug/assets/schemas/helmrelease-helm-v2.json index 885e724e1..5cd8695c1 100644 --- a/.agents/skills/gitops-cluster-debug/assets/schemas/helmrelease-helm-v2.json +++ b/.agents/skills/gitops-cluster-debug/assets/schemas/helmrelease-helm-v2.json @@ -651,7 +651,7 @@ "type": "boolean" }, "force": { - "description": "Force forces resource updates through a replacement strategy.", + "description": "Force forces resource updates through a replacement strategy\nthat avoids 3-way merge conflicts on client-side apply.\nThis field is ignored for server-side apply (which always\nforces conflicts with other field managers).", "type": "boolean" }, "recreate": { @@ -822,7 +822,7 @@ "type": "boolean" }, "force": { - "description": "Force forces resource updates through a replacement strategy.", + "description": "Force forces resource updates through a replacement strategy\nthat avoids 3-way merge conflicts on client-side apply.\nThis field is ignored for server-side apply (which always\nforces conflicts with other field managers).", "type": "boolean" }, "preserveValues": { diff --git a/.agents/skills/gitops-cluster-debug/assets/schemas/receiver-notification-v1.json b/.agents/skills/gitops-cluster-debug/assets/schemas/receiver-notification-v1.json index ea548e1a5..90141f3a4 100644 --- a/.agents/skills/gitops-cluster-debug/assets/schemas/receiver-notification-v1.json +++ b/.agents/skills/gitops-cluster-debug/assets/schemas/receiver-notification-v1.json @@ -89,7 +89,7 @@ "type": "array" }, "secretRef": { - "description": "SecretRef specifies the Secret containing the token used\nto validate the payload authenticity. The Secret must contain a 'token'\nkey. For GCR receivers, the Secret must also contain an 'email' key\nwith the IAM service account email configured on the Pub/Sub push\nsubscription, and may optionally contain an 'audience' key with the\nexpected OIDC token audience.", + "description": "SecretRef specifies the Secret containing the token used\nto validate the payload authenticity. The Secret must contain a 'token'\nkey. For GCR receivers, the Secret must also contain an 'email' key\nwith the IAM service account email configured on the Pub/Sub push\nsubscription, and an 'audience' key with the expected OIDC token audience.", "properties": { "name": { "description": "Name of the referent.", diff --git a/.agents/skills/gitops-cluster-debug/assets/schemas/resourceset-fluxcd-v1.json b/.agents/skills/gitops-cluster-debug/assets/schemas/resourceset-fluxcd-v1.json index 8dd944ce3..f55e30eea 100644 --- a/.agents/skills/gitops-cluster-debug/assets/schemas/resourceset-fluxcd-v1.json +++ b/.agents/skills/gitops-cluster-debug/assets/schemas/resourceset-fluxcd-v1.json @@ -13,9 +13,11 @@ "type": "object" }, "spec": { + "additionalProperties": false, "description": "ResourceSetSpec defines the desired state of ResourceSet", "properties": { "commonMetadata": { + "additionalProperties": false, "description": "CommonMetadata specifies the common labels and annotations that are\napplied to all resources. Any existing label or annotation will be\noverridden if its key matches a common one.", "properties": { "annotations": { @@ -33,12 +35,12 @@ "type": "object" } }, - "type": "object", - "additionalProperties": false + "type": "object" }, "dependsOn": { "description": "DependsOn specifies the list of Kubernetes resources that must\nexist on the cluster before the reconciliation process starts.", "items": { + "additionalProperties": false, "description": "Dependency defines a ResourceSet dependency on a Kubernetes resource.", "properties": { "apiVersion": { @@ -71,14 +73,18 @@ "kind", "name" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" }, "inputStrategy": { + "additionalProperties": false, "description": "InputStrategy defines how the inputs are combined when multiple\ninput provider objects are used. Defaults to flattening all inputs\nfrom all providers into a single list of input sets.", "properties": { + "includeEmptyProviders": { + "description": "IncludeEmptyProviders controls how input providers that export no\ninputs are treated. Only applies when Name is Permute. When true, if\nany provider has zero inputs the resulting permutation set is empty\n(mathematically correct Cartesian product behavior). When false or\nunset (default), providers with zero inputs are silently skipped and\nthe remaining providers still permute among themselves.", + "type": "boolean" + }, "name": { "description": "Name defines how the inputs are combined when multiple\ninput provider objects are used. Supported values are:\n- Flatten: all inputs sets from all input provider objects are\n flattened into a single list of input sets.\n- Permute: all inputs sets from all input provider objects are\n combined using a Cartesian product, resulting in a list of input sets\n that contains every possible combination of input values.\n For example, if provider A has inputs [{x: 1}, {x: 2}] and provider B has\n inputs [{y: \"a\"}, {y: \"b\"}], the resulting input sets will be:\n [{x: 1, y: \"a\"}, {x: 1, y: \"b\"}, {x: 2, y: \"a\"}, {x: 2, y: \"b\"}].\n This strategy can lead to a large number of input sets and should be\n used with caution. Users should use filtering features from\n ResourceSetInputProvider to limit the amount of exported inputs.", "enum": [ @@ -92,7 +98,12 @@ "name" ], "type": "object", - "additionalProperties": false + "x-kubernetes-validations": [ + { + "message": "includeEmptyProviders only applies when name is Permute", + "rule": "!has(self.includeEmptyProviders) || self.name == 'Permute'" + } + ] }, "inputs": { "description": "Inputs contains the list of ResourceSet inputs.", @@ -108,6 +119,7 @@ "inputsFrom": { "description": "InputsFrom contains the list of references to input providers.\nWhen set, the inputs are fetched from the providers and concatenated\nwith the in-line inputs defined in the ResourceSet.", "items": { + "additionalProperties": false, "description": "InputProviderReference defines a reference to an input provider resource\nin the same namespace as the ResourceSet.", "properties": { "apiVersion": { @@ -129,11 +141,13 @@ "type": "string" }, "selector": { + "additionalProperties": false, "description": "Selector is a label selector to filter the input provider resources\nas an alternative to the Name field.", "properties": { "matchExpressions": { "description": "matchExpressions is a list of label selector requirements. The requirements are ANDed.", "items": { + "additionalProperties": false, "description": "A label selector requirement is a selector that contains values, a key, and an operator that\nrelates the key and values.", "properties": { "key": { @@ -157,8 +171,7 @@ "key", "operator" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array", "x-kubernetes-list-type": "atomic" @@ -172,8 +185,7 @@ } }, "type": "object", - "x-kubernetes-map-type": "atomic", - "additionalProperties": false + "x-kubernetes-map-type": "atomic" } }, "type": "object", @@ -186,8 +198,7 @@ "message": "cannot set both name and selector for input provider references", "rule": "!has(self.name) || !has(self.selector)" } - ], - "additionalProperties": false + ] }, "type": "array" }, @@ -211,15 +222,16 @@ "type": "boolean" } }, - "type": "object", - "additionalProperties": false + "type": "object" }, "status": { + "additionalProperties": false, "description": "ResourceSetStatus defines the observed state of ResourceSet.", "properties": { "conditions": { "description": "Conditions contains the readiness conditions of the object.", "items": { + "additionalProperties": false, "description": "Condition contains details for one aspect of the current state of this API Resource.", "properties": { "lastTransitionTime": { @@ -268,14 +280,21 @@ "status", "type" ], - "type": "object", - "additionalProperties": false + "type": "object" + }, + "type": "array" + }, + "externalChecksumRefs": { + "description": "ExternalChecksumRefs lists the ConfigMap and Secret references\ndiscovered in checksumFrom annotations on the last reconciliation\nthat point to objects not rendered by this ResourceSet. Each entry\nhas the form \"Kind/namespace/name\". It is used to trigger a\nreconciliation when one of the referenced objects changes.", + "items": { + "type": "string" }, "type": "array" }, "history": { "description": "History contains the reconciliation history of the ResourceSet\nas a list of snapshots ordered by the last reconciled time.", "items": { + "additionalProperties": false, "description": "Snapshot represents a point-in-time record of a group of resources reconciliation,\nincluding timing information, status, and a unique digest identifier.", "properties": { "digest": { @@ -321,17 +340,18 @@ "lastReconciledStatus", "totalReconciliations" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" }, "inventory": { + "additionalProperties": false, "description": "Inventory contains a list of Kubernetes resource object references\nlast applied on the cluster.", "properties": { "entries": { "description": "Entries of Kubernetes resource object references.", "items": { + "additionalProperties": false, "description": "ResourceRef contains the information necessary to locate a resource within a cluster.", "properties": { "id": { @@ -347,8 +367,7 @@ "id", "v" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" } @@ -356,8 +375,7 @@ "required": [ "entries" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "lastAppliedRevision": { "description": "LastAppliedRevision is the digest of the\ngenerated resources that were last reconcile.", @@ -368,9 +386,8 @@ "type": "string" } }, - "type": "object", - "additionalProperties": false + "type": "object" } }, "type": "object" -} \ No newline at end of file +} diff --git a/.agents/skills/gitops-cluster-debug/assets/schemas/resourcesetinputprovider-fluxcd-v1.json b/.agents/skills/gitops-cluster-debug/assets/schemas/resourcesetinputprovider-fluxcd-v1.json index 872ca7a8d..5e98e35dc 100644 --- a/.agents/skills/gitops-cluster-debug/assets/schemas/resourcesetinputprovider-fluxcd-v1.json +++ b/.agents/skills/gitops-cluster-debug/assets/schemas/resourcesetinputprovider-fluxcd-v1.json @@ -13,9 +13,11 @@ "type": "object" }, "spec": { + "additionalProperties": false, "description": "ResourceSetInputProviderSpec defines the desired state of ResourceSetInputProvider", "properties": { "certSecretRef": { + "additionalProperties": false, "description": "CertSecretRef specifies the Kubernetes Secret containing either or both of\n\n- a PEM-encoded CA certificate (`ca.crt`)\n- a PEM-encoded client certificate (`tls.crt`) and private key (`tls.key`)\n\nWhen connecting to a Git, OCI, or ExternalService provider that uses self-signed certificates,\nthe CA certificate must be set in the Secret under the 'ca.crt' key to establish the trust relationship.\nWhen connecting to a provider that supports client certificates (mTLS), the client certificate\nand private key must be set in the Secret under the 'tls.crt' and 'tls.key' keys, respectively.", "properties": { "name": { @@ -26,8 +28,7 @@ "required": [ "name" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "defaultValues": { "additionalProperties": { @@ -37,6 +38,7 @@ "type": "object" }, "filter": { + "additionalProperties": false, "description": "Filter defines the filter to apply to the input provider response.", "properties": { "excludeBranch": { @@ -80,8 +82,7 @@ "type": "string" } }, - "type": "object", - "additionalProperties": false + "type": "object" }, "insecure": { "description": "Insecure allows connecting to an ExternalService or OCIArtifactTag provider\nover plain HTTP without TLS. When not set, the URL must use HTTPS.", @@ -90,6 +91,7 @@ "schedule": { "description": "Schedule defines the schedules for the input provider to run.", "items": { + "additionalProperties": false, "description": "Schedule defines a schedule for something to run.", "properties": { "cron": { @@ -111,12 +113,12 @@ "required": [ "cron" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" }, "secretRef": { + "additionalProperties": false, "description": "SecretRef specifies the Kubernetes Secret containing the credentials\nto access the input provider.\nWhen connecting to a Git provider, the secret must contain the keys\n'username' and 'password', and the password should be a personal access token\nthat grants read-only access to the repository.\nWhen connecting to an OCI provider, the secret must contain a Kubernetes\nImage Pull Secret, as if created by `kubectl create secret docker-registry`.\nWhen connecting to an ExternalService provider, the secret must contain either\na 'token' key for bearer token authentication, or 'username' and 'password'\nkeys for basic authentication.", "properties": { "name": { @@ -127,14 +129,14 @@ "required": [ "name" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "serviceAccountName": { "description": "ServiceAccountName specifies the name of the Kubernetes ServiceAccount\nused for authentication with AWS, Azure or GCP services through\nworkload identity federation features. If not specified, the\nauthentication for these cloud providers will use the ServiceAccount\nof the operator (or any other environment authentication configuration).", "type": "string" }, "skip": { + "additionalProperties": false, "description": "Skip defines whether we need to skip input provider response updates.", "properties": { "labels": { @@ -145,8 +147,7 @@ "type": "array" } }, - "type": "object", - "additionalProperties": false + "type": "object" }, "type": { "description": "Type specifies the type of the input provider.", @@ -162,6 +163,9 @@ "AzureDevOpsBranch", "AzureDevOpsTag", "AzureDevOpsPullRequest", + "AWSCodeCommitBranch", + "AWSCodeCommitTag", + "AWSCodeCommitPullRequest", "GiteaBranch", "GiteaTag", "GiteaPullRequest", @@ -197,8 +201,12 @@ "rule": "!self.type.startsWith('Git') || self.url.startsWith('http')" }, { - "message": "spec.url must start with 'http://' or 'https://' when spec.type is a Git provider", - "rule": "!self.type.startsWith('AzureDevOps') || self.url.startsWith('http')" + "message": "spec.url must start with 'http://' or 'https://' when spec.type is an AzureDevOps provider", + "rule": "!self.type.startsWith('AzureDevOps') || self.url.startsWith('http://') || self.url.startsWith('https://')" + }, + { + "message": "spec.url must start with 'https://' when spec.type is a AWSCodeCommit provider", + "rule": "!self.type.startsWith('AWSCodeCommit') || self.url.startsWith('https://')" }, { "message": "spec.url must start with 'oci://' when spec.type is an OCI provider", @@ -217,26 +225,27 @@ "rule": "self.type != 'ExternalService' || !self.url.startsWith('http://') || (has(self.insecure) && self.insecure)" }, { - "message": "cannot specify spec.serviceAccountName when spec.type is not one of AzureDevOps* or *ArtifactTag", - "rule": "!has(self.serviceAccountName) || self.type.startsWith('AzureDevOps') || self.type.endsWith('ArtifactTag')" + "message": "cannot specify spec.serviceAccountName when spec.type is not one of AzureDevOps*, AWSCodeCommit* or *ArtifactTag", + "rule": "!has(self.serviceAccountName) || self.type.startsWith('AzureDevOps') || self.type.startsWith('AWSCodeCommit') || self.type.endsWith('ArtifactTag')" }, { - "message": "cannot specify spec.certSecretRef when spec.type is one of Static, AzureDevOps*, ACRArtifactTag, ECRArtifactTag or GARArtifactTag", - "rule": "!has(self.certSecretRef) || !(self.url == 'Static' || self.type.startsWith('AzureDevOps') || (self.type.endsWith('ArtifactTag') && self.type != 'OCIArtifactTag'))" + "message": "cannot specify spec.certSecretRef when spec.type is one of Static, AzureDevOps*, AWSCodeCommit*, ACRArtifactTag, ECRArtifactTag or GARArtifactTag", + "rule": "!has(self.certSecretRef) || !(self.url == 'Static' || self.type.startsWith('AzureDevOps') || self.type.startsWith('AWSCodeCommit') || (self.type.endsWith('ArtifactTag') && self.type != 'OCIArtifactTag'))" }, { - "message": "cannot specify spec.secretRef when spec.type is one of Static, ACRArtifactTag, ECRArtifactTag or GARArtifactTag", - "rule": "!has(self.secretRef) || !(self.url == 'Static' || (self.type.endsWith('ArtifactTag') && self.type != 'OCIArtifactTag'))" + "message": "cannot specify spec.secretRef when spec.type is one of Static, AWSCodeCommit*, ACRArtifactTag, ECRArtifactTag or GARArtifactTag", + "rule": "!has(self.secretRef) || !(self.url == 'Static' || self.type.startsWith('AWSCodeCommit') || (self.type.endsWith('ArtifactTag') && self.type != 'OCIArtifactTag'))" } - ], - "additionalProperties": false + ] }, "status": { + "additionalProperties": false, "description": "ResourceSetInputProviderStatus defines the observed state of ResourceSetInputProvider.", "properties": { "conditions": { "description": "Conditions contains the readiness conditions of the object.", "items": { + "additionalProperties": false, "description": "Condition contains details for one aspect of the current state of this API Resource.", "properties": { "lastTransitionTime": { @@ -285,8 +294,7 @@ "status", "type" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" }, @@ -314,6 +322,7 @@ "type": "string" }, "nextSchedule": { + "additionalProperties": false, "description": "NextSchedule is the next schedule when the input provider will run.", "properties": { "cron": { @@ -341,13 +350,11 @@ "cron", "when" ], - "type": "object", - "additionalProperties": false + "type": "object" } }, - "type": "object", - "additionalProperties": false + "type": "object" } }, "type": "object" -} \ No newline at end of file +} diff --git a/.agents/skills/gitops-knowledge/SKILL.md b/.agents/skills/gitops-knowledge/SKILL.md index d0136e6f9..19f801b0d 100644 --- a/.agents/skills/gitops-knowledge/SKILL.md +++ b/.agents/skills/gitops-knowledge/SKILL.md @@ -4,9 +4,9 @@ description: | license: Apache-2.0 metadata: github-path: skills/gitops-knowledge - github-ref: refs/tags/v0.0.3 + github-ref: refs/tags/v0.0.4 github-repo: https://github.com/fluxcd/agent-skills - github-tree-sha: 7edabe6723319a256d8aa31ad80a5969c3c521c4 + github-tree-sha: 87c84bc20bf3a0356deb68be41334149eb9a4371 name: gitops-knowledge --- # Flux CD Knowledge Base @@ -321,46 +321,17 @@ kind: ResourceSet metadata: name: apps namespace: flux-system - annotations: - fluxcd.controlplane.io/reconcileEvery: "5m" spec: - dependsOn: - - apiVersion: fluxcd.controlplane.io/v1 - kind: ResourceSet - name: infra - ready: true inputs: - tenant: "frontend" - tag: "latest" environment: "production" - tenant: "backend" - tag: "latest" environment: "production" resources: - apiVersion: v1 kind: Namespace metadata: name: << inputs.tenant >> - labels: - toolkit.fluxcd.io/role: "tenant" - - apiVersion: v1 - kind: ServiceAccount - metadata: - name: flux - namespace: << inputs.tenant >> - - apiVersion: rbac.authorization.k8s.io/v1 - kind: RoleBinding - metadata: - name: flux - namespace: << inputs.tenant >> - roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: admin - subjects: - - kind: ServiceAccount - name: flux - namespace: << inputs.tenant >> - apiVersion: source.toolkit.fluxcd.io/v1 kind: OCIRepository metadata: @@ -370,26 +341,26 @@ spec: interval: 5m url: "oci://ghcr.io/my-org/apps/<< inputs.tenant >>" ref: - tag: << inputs.tag >> + tag: latest - apiVersion: kustomize.toolkit.fluxcd.io/v1 kind: Kustomization metadata: name: apps namespace: << inputs.tenant >> spec: - targetNamespace: << inputs.tenant >> - serviceAccountName: flux interval: 30m - retryInterval: 5m wait: true - timeout: 5m + prune: true sourceRef: kind: OCIRepository name: apps path: "./<< inputs.environment >>" - prune: true ``` +For the full multi-tenant pattern — per-tenant ServiceAccount + RoleBinding, +`serviceAccountName` impersonation, `dependsOn`, and the `reconcileEvery` annotation — +load `references/resourcesets.md`. + ### 6. Image Automation Flux supports two delivery models for updating container images and Helm chart versions. @@ -475,4 +446,5 @@ Load at most 1-2 reference files per question. Read schemas for field-level vali | Web UI, dashboard, SSO, OIDC, Dex, Keycloak, Entra ID, RBAC | `references/web-ui.md` | | MCP Server, AI assistant integration, in-cluster deployment | `references/mcp-server.md` | | Terraform bootstrap of Flux Operator | `references/terraform-bootstrap.md` | +| Gitless GitOps, Flux OCI artifacts, `flux push artifact`, registry-based delivery | `references/gitless-gitops.md` | | Gitless image automation (ResourceSet + OCIArtifactTag) | `references/gitless-image-automation.md` | diff --git a/.agents/skills/gitops-knowledge/assets/schemas/fluxinstance-fluxcd-v1.json b/.agents/skills/gitops-knowledge/assets/schemas/fluxinstance-fluxcd-v1.json index 1f6e9a51d..1635135e4 100644 --- a/.agents/skills/gitops-knowledge/assets/schemas/fluxinstance-fluxcd-v1.json +++ b/.agents/skills/gitops-knowledge/assets/schemas/fluxinstance-fluxcd-v1.json @@ -13,9 +13,11 @@ "type": "object" }, "spec": { + "additionalProperties": false, "description": "FluxInstanceSpec defines the desired state of FluxInstance", "properties": { "cluster": { + "additionalProperties": false, "description": "Cluster holds the specification of the Kubernetes cluster.", "properties": { "domain": { @@ -82,10 +84,10 @@ "message": ".objectLevelWorkloadIdentity must be set to true when .multitenantWorkloadIdentity is set to true", "rule": "(has(self.objectLevelWorkloadIdentity) && self.objectLevelWorkloadIdentity) || !has(self.multitenantWorkloadIdentity) || !self.multitenantWorkloadIdentity" } - ], - "additionalProperties": false + ] }, "commonMetadata": { + "additionalProperties": false, "description": "CommonMetadata specifies the common labels and annotations that are\napplied to all resources. Any existing label or annotation will be\noverridden if its key matches a common one.", "properties": { "annotations": { @@ -103,8 +105,7 @@ "type": "object" } }, - "type": "object", - "additionalProperties": false + "type": "object" }, "components": { "description": "Components is the list of controllers to install.\nDefaults to the core Flux controllers:\n - source-controller\n - kustomize-controller\n - helm-controller\n - notification-controller", @@ -124,6 +125,7 @@ "type": "array" }, "distribution": { + "additionalProperties": false, "description": "Distribution specifies the version and container registry to pull images from.", "properties": { "artifact": { @@ -162,15 +164,16 @@ "registry", "version" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "kustomize": { + "additionalProperties": false, "description": "Kustomize holds a set of patches that can be applied to the\nFlux installation, to customize the way Flux operates.", "properties": { "patches": { "description": "Strategic merge and JSON patches, defined as inline YAML objects,\ncapable of targeting objects based on kind, label and annotation selectors.", "items": { + "additionalProperties": false, "description": "Patch contains an inline StrategicMerge or JSON6902 patch, and the target the patch should\nbe applied to.", "properties": { "patch": { @@ -178,6 +181,7 @@ "type": "string" }, "target": { + "additionalProperties": false, "description": "Target points to the resources that the patch document should be applied to.", "properties": { "annotationSelector": { @@ -209,21 +213,18 @@ "type": "string" } }, - "type": "object", - "additionalProperties": false + "type": "object" } }, "required": [ "patch" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" } }, - "type": "object", - "additionalProperties": false + "type": "object" }, "migrateResources": { "default": true, @@ -231,6 +232,7 @@ "type": "boolean" }, "sharding": { + "additionalProperties": false, "description": "Sharding holds the specification of the sharding configuration.", "properties": { "key": { @@ -258,10 +260,10 @@ "required": [ "shards" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "storage": { + "additionalProperties": false, "description": "Storage holds the specification of the source-controller\npersistent volume claim.", "properties": { "class": { @@ -277,10 +279,10 @@ "class", "size" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "sync": { + "additionalProperties": false, "description": "Sync specifies the source for the cluster sync operation.\nWhen set, a Flux source (GitRepository, OCIRepository or Bucket)\nand Flux Kustomization are created to sync the cluster state\nwith the source repository.", "properties": { "interval": { @@ -314,7 +316,7 @@ "type": "string" }, "provider": { - "description": "Provider specifies OIDC provider for source authentication.\nFor OCIRepository and Bucket the provider can be set to 'aws', 'azure' or 'gcp'.\nfor GitRepository the accepted value can be set to 'azure' or 'github'.\nTo disable OIDC authentication the provider can be set to 'generic' or left empty.", + "description": "Provider specifies OIDC provider for source authentication.\nFor OCIRepository and Bucket the provider can be set to 'aws', 'azure' or 'gcp'.\nFor GitRepository the provider can be set to 'aws' (requires Flux 2.9 or later),\n'azure' or 'github'.\nTo disable OIDC authentication the provider can be set to 'generic' or left empty.", "enum": [ "generic", "aws", @@ -344,7 +346,16 @@ "url" ], "type": "object", - "additionalProperties": false + "x-kubernetes-validations": [ + { + "message": "sync.provider 'gcp' is only supported for OCIRepository and Bucket", + "rule": "!has(self.provider) || self.provider != 'gcp' || self.kind == 'OCIRepository' || self.kind == 'Bucket'" + }, + { + "message": "sync.provider 'github' is only supported for GitRepository", + "rule": "!has(self.provider) || self.provider != 'github' || self.kind == 'GitRepository'" + } + ] }, "wait": { "default": true, @@ -355,15 +366,16 @@ "required": [ "distribution" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "status": { + "additionalProperties": false, "description": "FluxInstanceStatus defines the observed state of FluxInstance", "properties": { "components": { "description": "Components contains the container images used by the components.", "items": { + "additionalProperties": false, "description": "ComponentImage represents a container image used by a component.", "properties": { "digest": { @@ -388,14 +400,14 @@ "repository", "tag" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" }, "conditions": { "description": "Conditions contains the readiness conditions of the object.", "items": { + "additionalProperties": false, "description": "Condition contains details for one aspect of the current state of this API Resource.", "properties": { "lastTransitionTime": { @@ -444,14 +456,14 @@ "status", "type" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" }, "history": { "description": "History contains the reconciliation history of the FluxInstance\nas a list of snapshots ordered by the last reconciled time.", "items": { + "additionalProperties": false, "description": "Snapshot represents a point-in-time record of a group of resources reconciliation,\nincluding timing information, status, and a unique digest identifier.", "properties": { "digest": { @@ -497,17 +509,18 @@ "lastReconciledStatus", "totalReconciliations" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" }, "inventory": { + "additionalProperties": false, "description": "Inventory contains a list of Kubernetes resource object references\nlast applied on the cluster.", "properties": { "entries": { "description": "Entries of Kubernetes resource object references.", "items": { + "additionalProperties": false, "description": "ResourceRef contains the information necessary to locate a resource within a cluster.", "properties": { "id": { @@ -523,8 +536,7 @@ "id", "v" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" } @@ -532,8 +544,7 @@ "required": [ "entries" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "lastAppliedRevision": { "description": "LastAppliedRevision is the version and digest of the\ndistribution config that was last reconcile.", @@ -556,8 +567,7 @@ "type": "string" } }, - "type": "object", - "additionalProperties": false + "type": "object" } }, "type": "object", @@ -567,4 +577,4 @@ "rule": "self.metadata.name == 'flux'" } ] -} \ No newline at end of file +} diff --git a/.agents/skills/gitops-knowledge/assets/schemas/fluxreport-fluxcd-v1.json b/.agents/skills/gitops-knowledge/assets/schemas/fluxreport-fluxcd-v1.json index a7f6fc861..e7b9876d4 100644 --- a/.agents/skills/gitops-knowledge/assets/schemas/fluxreport-fluxcd-v1.json +++ b/.agents/skills/gitops-knowledge/assets/schemas/fluxreport-fluxcd-v1.json @@ -13,9 +13,11 @@ "type": "object" }, "spec": { + "additionalProperties": false, "description": "FluxReportSpec defines the observed state of a Flux installation.", "properties": { "cluster": { + "additionalProperties": false, "description": "Cluster is the version information of the Kubernetes cluster.", "properties": { "nodes": { @@ -35,12 +37,12 @@ "platform", "serverVersion" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "components": { "description": "ComponentsStatus is the status of the Flux controller deployments.", "items": { + "additionalProperties": false, "description": "FluxComponentStatus defines the observed state of a Flux component.", "properties": { "image": { @@ -66,12 +68,12 @@ "ready", "status" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" }, "distribution": { + "additionalProperties": false, "description": "Distribution is the version information of the Flux installation.", "properties": { "entitlement": { @@ -95,10 +97,10 @@ "entitlement", "status" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "operator": { + "additionalProperties": false, "description": "Operator is the version information of the Flux Operator.", "properties": { "apiVersion": { @@ -119,12 +121,12 @@ "platform", "version" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "reconcilers": { "description": "ReconcilersStatus is the list of Flux reconcilers and\ntheir statistics grouped by API kind.", "items": { + "additionalProperties": false, "description": "FluxReconcilerStatus defines the observed state of a Flux reconciler.", "properties": { "apiVersion": { @@ -136,6 +138,7 @@ "type": "string" }, "stats": { + "additionalProperties": false, "description": "Stats is the reconcile statics of the Flux resource kind.", "properties": { "failing": { @@ -160,20 +163,19 @@ "running", "suspended" ], - "type": "object", - "additionalProperties": false + "type": "object" } }, "required": [ "apiVersion", "kind" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" }, "sync": { + "additionalProperties": false, "description": "SyncStatus is the status of the cluster sync\nSource and Kustomization resources.", "properties": { "id": { @@ -202,22 +204,22 @@ "ready", "status" ], - "type": "object", - "additionalProperties": false + "type": "object" } }, "required": [ "distribution" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "status": { + "additionalProperties": false, "description": "FluxReportStatus defines the readiness of a FluxReport.", "properties": { "conditions": { "description": "Conditions contains the readiness conditions of the object.", "items": { + "additionalProperties": false, "description": "Condition contains details for one aspect of the current state of this API Resource.", "properties": { "lastTransitionTime": { @@ -266,8 +268,7 @@ "status", "type" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" }, @@ -276,8 +277,7 @@ "type": "string" } }, - "type": "object", - "additionalProperties": false + "type": "object" } }, "type": "object", @@ -287,4 +287,4 @@ "rule": "self.metadata.name == 'flux'" } ] -} \ No newline at end of file +} diff --git a/.agents/skills/gitops-knowledge/assets/schemas/helmrelease-helm-v2.json b/.agents/skills/gitops-knowledge/assets/schemas/helmrelease-helm-v2.json index 885e724e1..5cd8695c1 100644 --- a/.agents/skills/gitops-knowledge/assets/schemas/helmrelease-helm-v2.json +++ b/.agents/skills/gitops-knowledge/assets/schemas/helmrelease-helm-v2.json @@ -651,7 +651,7 @@ "type": "boolean" }, "force": { - "description": "Force forces resource updates through a replacement strategy.", + "description": "Force forces resource updates through a replacement strategy\nthat avoids 3-way merge conflicts on client-side apply.\nThis field is ignored for server-side apply (which always\nforces conflicts with other field managers).", "type": "boolean" }, "recreate": { @@ -822,7 +822,7 @@ "type": "boolean" }, "force": { - "description": "Force forces resource updates through a replacement strategy.", + "description": "Force forces resource updates through a replacement strategy\nthat avoids 3-way merge conflicts on client-side apply.\nThis field is ignored for server-side apply (which always\nforces conflicts with other field managers).", "type": "boolean" }, "preserveValues": { diff --git a/.agents/skills/gitops-knowledge/assets/schemas/receiver-notification-v1.json b/.agents/skills/gitops-knowledge/assets/schemas/receiver-notification-v1.json index ea548e1a5..90141f3a4 100644 --- a/.agents/skills/gitops-knowledge/assets/schemas/receiver-notification-v1.json +++ b/.agents/skills/gitops-knowledge/assets/schemas/receiver-notification-v1.json @@ -89,7 +89,7 @@ "type": "array" }, "secretRef": { - "description": "SecretRef specifies the Secret containing the token used\nto validate the payload authenticity. The Secret must contain a 'token'\nkey. For GCR receivers, the Secret must also contain an 'email' key\nwith the IAM service account email configured on the Pub/Sub push\nsubscription, and may optionally contain an 'audience' key with the\nexpected OIDC token audience.", + "description": "SecretRef specifies the Secret containing the token used\nto validate the payload authenticity. The Secret must contain a 'token'\nkey. For GCR receivers, the Secret must also contain an 'email' key\nwith the IAM service account email configured on the Pub/Sub push\nsubscription, and an 'audience' key with the expected OIDC token audience.", "properties": { "name": { "description": "Name of the referent.", diff --git a/.agents/skills/gitops-knowledge/assets/schemas/resourceset-fluxcd-v1.json b/.agents/skills/gitops-knowledge/assets/schemas/resourceset-fluxcd-v1.json index 8dd944ce3..f55e30eea 100644 --- a/.agents/skills/gitops-knowledge/assets/schemas/resourceset-fluxcd-v1.json +++ b/.agents/skills/gitops-knowledge/assets/schemas/resourceset-fluxcd-v1.json @@ -13,9 +13,11 @@ "type": "object" }, "spec": { + "additionalProperties": false, "description": "ResourceSetSpec defines the desired state of ResourceSet", "properties": { "commonMetadata": { + "additionalProperties": false, "description": "CommonMetadata specifies the common labels and annotations that are\napplied to all resources. Any existing label or annotation will be\noverridden if its key matches a common one.", "properties": { "annotations": { @@ -33,12 +35,12 @@ "type": "object" } }, - "type": "object", - "additionalProperties": false + "type": "object" }, "dependsOn": { "description": "DependsOn specifies the list of Kubernetes resources that must\nexist on the cluster before the reconciliation process starts.", "items": { + "additionalProperties": false, "description": "Dependency defines a ResourceSet dependency on a Kubernetes resource.", "properties": { "apiVersion": { @@ -71,14 +73,18 @@ "kind", "name" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" }, "inputStrategy": { + "additionalProperties": false, "description": "InputStrategy defines how the inputs are combined when multiple\ninput provider objects are used. Defaults to flattening all inputs\nfrom all providers into a single list of input sets.", "properties": { + "includeEmptyProviders": { + "description": "IncludeEmptyProviders controls how input providers that export no\ninputs are treated. Only applies when Name is Permute. When true, if\nany provider has zero inputs the resulting permutation set is empty\n(mathematically correct Cartesian product behavior). When false or\nunset (default), providers with zero inputs are silently skipped and\nthe remaining providers still permute among themselves.", + "type": "boolean" + }, "name": { "description": "Name defines how the inputs are combined when multiple\ninput provider objects are used. Supported values are:\n- Flatten: all inputs sets from all input provider objects are\n flattened into a single list of input sets.\n- Permute: all inputs sets from all input provider objects are\n combined using a Cartesian product, resulting in a list of input sets\n that contains every possible combination of input values.\n For example, if provider A has inputs [{x: 1}, {x: 2}] and provider B has\n inputs [{y: \"a\"}, {y: \"b\"}], the resulting input sets will be:\n [{x: 1, y: \"a\"}, {x: 1, y: \"b\"}, {x: 2, y: \"a\"}, {x: 2, y: \"b\"}].\n This strategy can lead to a large number of input sets and should be\n used with caution. Users should use filtering features from\n ResourceSetInputProvider to limit the amount of exported inputs.", "enum": [ @@ -92,7 +98,12 @@ "name" ], "type": "object", - "additionalProperties": false + "x-kubernetes-validations": [ + { + "message": "includeEmptyProviders only applies when name is Permute", + "rule": "!has(self.includeEmptyProviders) || self.name == 'Permute'" + } + ] }, "inputs": { "description": "Inputs contains the list of ResourceSet inputs.", @@ -108,6 +119,7 @@ "inputsFrom": { "description": "InputsFrom contains the list of references to input providers.\nWhen set, the inputs are fetched from the providers and concatenated\nwith the in-line inputs defined in the ResourceSet.", "items": { + "additionalProperties": false, "description": "InputProviderReference defines a reference to an input provider resource\nin the same namespace as the ResourceSet.", "properties": { "apiVersion": { @@ -129,11 +141,13 @@ "type": "string" }, "selector": { + "additionalProperties": false, "description": "Selector is a label selector to filter the input provider resources\nas an alternative to the Name field.", "properties": { "matchExpressions": { "description": "matchExpressions is a list of label selector requirements. The requirements are ANDed.", "items": { + "additionalProperties": false, "description": "A label selector requirement is a selector that contains values, a key, and an operator that\nrelates the key and values.", "properties": { "key": { @@ -157,8 +171,7 @@ "key", "operator" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array", "x-kubernetes-list-type": "atomic" @@ -172,8 +185,7 @@ } }, "type": "object", - "x-kubernetes-map-type": "atomic", - "additionalProperties": false + "x-kubernetes-map-type": "atomic" } }, "type": "object", @@ -186,8 +198,7 @@ "message": "cannot set both name and selector for input provider references", "rule": "!has(self.name) || !has(self.selector)" } - ], - "additionalProperties": false + ] }, "type": "array" }, @@ -211,15 +222,16 @@ "type": "boolean" } }, - "type": "object", - "additionalProperties": false + "type": "object" }, "status": { + "additionalProperties": false, "description": "ResourceSetStatus defines the observed state of ResourceSet.", "properties": { "conditions": { "description": "Conditions contains the readiness conditions of the object.", "items": { + "additionalProperties": false, "description": "Condition contains details for one aspect of the current state of this API Resource.", "properties": { "lastTransitionTime": { @@ -268,14 +280,21 @@ "status", "type" ], - "type": "object", - "additionalProperties": false + "type": "object" + }, + "type": "array" + }, + "externalChecksumRefs": { + "description": "ExternalChecksumRefs lists the ConfigMap and Secret references\ndiscovered in checksumFrom annotations on the last reconciliation\nthat point to objects not rendered by this ResourceSet. Each entry\nhas the form \"Kind/namespace/name\". It is used to trigger a\nreconciliation when one of the referenced objects changes.", + "items": { + "type": "string" }, "type": "array" }, "history": { "description": "History contains the reconciliation history of the ResourceSet\nas a list of snapshots ordered by the last reconciled time.", "items": { + "additionalProperties": false, "description": "Snapshot represents a point-in-time record of a group of resources reconciliation,\nincluding timing information, status, and a unique digest identifier.", "properties": { "digest": { @@ -321,17 +340,18 @@ "lastReconciledStatus", "totalReconciliations" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" }, "inventory": { + "additionalProperties": false, "description": "Inventory contains a list of Kubernetes resource object references\nlast applied on the cluster.", "properties": { "entries": { "description": "Entries of Kubernetes resource object references.", "items": { + "additionalProperties": false, "description": "ResourceRef contains the information necessary to locate a resource within a cluster.", "properties": { "id": { @@ -347,8 +367,7 @@ "id", "v" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" } @@ -356,8 +375,7 @@ "required": [ "entries" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "lastAppliedRevision": { "description": "LastAppliedRevision is the digest of the\ngenerated resources that were last reconcile.", @@ -368,9 +386,8 @@ "type": "string" } }, - "type": "object", - "additionalProperties": false + "type": "object" } }, "type": "object" -} \ No newline at end of file +} diff --git a/.agents/skills/gitops-knowledge/assets/schemas/resourcesetinputprovider-fluxcd-v1.json b/.agents/skills/gitops-knowledge/assets/schemas/resourcesetinputprovider-fluxcd-v1.json index 872ca7a8d..5e98e35dc 100644 --- a/.agents/skills/gitops-knowledge/assets/schemas/resourcesetinputprovider-fluxcd-v1.json +++ b/.agents/skills/gitops-knowledge/assets/schemas/resourcesetinputprovider-fluxcd-v1.json @@ -13,9 +13,11 @@ "type": "object" }, "spec": { + "additionalProperties": false, "description": "ResourceSetInputProviderSpec defines the desired state of ResourceSetInputProvider", "properties": { "certSecretRef": { + "additionalProperties": false, "description": "CertSecretRef specifies the Kubernetes Secret containing either or both of\n\n- a PEM-encoded CA certificate (`ca.crt`)\n- a PEM-encoded client certificate (`tls.crt`) and private key (`tls.key`)\n\nWhen connecting to a Git, OCI, or ExternalService provider that uses self-signed certificates,\nthe CA certificate must be set in the Secret under the 'ca.crt' key to establish the trust relationship.\nWhen connecting to a provider that supports client certificates (mTLS), the client certificate\nand private key must be set in the Secret under the 'tls.crt' and 'tls.key' keys, respectively.", "properties": { "name": { @@ -26,8 +28,7 @@ "required": [ "name" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "defaultValues": { "additionalProperties": { @@ -37,6 +38,7 @@ "type": "object" }, "filter": { + "additionalProperties": false, "description": "Filter defines the filter to apply to the input provider response.", "properties": { "excludeBranch": { @@ -80,8 +82,7 @@ "type": "string" } }, - "type": "object", - "additionalProperties": false + "type": "object" }, "insecure": { "description": "Insecure allows connecting to an ExternalService or OCIArtifactTag provider\nover plain HTTP without TLS. When not set, the URL must use HTTPS.", @@ -90,6 +91,7 @@ "schedule": { "description": "Schedule defines the schedules for the input provider to run.", "items": { + "additionalProperties": false, "description": "Schedule defines a schedule for something to run.", "properties": { "cron": { @@ -111,12 +113,12 @@ "required": [ "cron" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" }, "secretRef": { + "additionalProperties": false, "description": "SecretRef specifies the Kubernetes Secret containing the credentials\nto access the input provider.\nWhen connecting to a Git provider, the secret must contain the keys\n'username' and 'password', and the password should be a personal access token\nthat grants read-only access to the repository.\nWhen connecting to an OCI provider, the secret must contain a Kubernetes\nImage Pull Secret, as if created by `kubectl create secret docker-registry`.\nWhen connecting to an ExternalService provider, the secret must contain either\na 'token' key for bearer token authentication, or 'username' and 'password'\nkeys for basic authentication.", "properties": { "name": { @@ -127,14 +129,14 @@ "required": [ "name" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "serviceAccountName": { "description": "ServiceAccountName specifies the name of the Kubernetes ServiceAccount\nused for authentication with AWS, Azure or GCP services through\nworkload identity federation features. If not specified, the\nauthentication for these cloud providers will use the ServiceAccount\nof the operator (or any other environment authentication configuration).", "type": "string" }, "skip": { + "additionalProperties": false, "description": "Skip defines whether we need to skip input provider response updates.", "properties": { "labels": { @@ -145,8 +147,7 @@ "type": "array" } }, - "type": "object", - "additionalProperties": false + "type": "object" }, "type": { "description": "Type specifies the type of the input provider.", @@ -162,6 +163,9 @@ "AzureDevOpsBranch", "AzureDevOpsTag", "AzureDevOpsPullRequest", + "AWSCodeCommitBranch", + "AWSCodeCommitTag", + "AWSCodeCommitPullRequest", "GiteaBranch", "GiteaTag", "GiteaPullRequest", @@ -197,8 +201,12 @@ "rule": "!self.type.startsWith('Git') || self.url.startsWith('http')" }, { - "message": "spec.url must start with 'http://' or 'https://' when spec.type is a Git provider", - "rule": "!self.type.startsWith('AzureDevOps') || self.url.startsWith('http')" + "message": "spec.url must start with 'http://' or 'https://' when spec.type is an AzureDevOps provider", + "rule": "!self.type.startsWith('AzureDevOps') || self.url.startsWith('http://') || self.url.startsWith('https://')" + }, + { + "message": "spec.url must start with 'https://' when spec.type is a AWSCodeCommit provider", + "rule": "!self.type.startsWith('AWSCodeCommit') || self.url.startsWith('https://')" }, { "message": "spec.url must start with 'oci://' when spec.type is an OCI provider", @@ -217,26 +225,27 @@ "rule": "self.type != 'ExternalService' || !self.url.startsWith('http://') || (has(self.insecure) && self.insecure)" }, { - "message": "cannot specify spec.serviceAccountName when spec.type is not one of AzureDevOps* or *ArtifactTag", - "rule": "!has(self.serviceAccountName) || self.type.startsWith('AzureDevOps') || self.type.endsWith('ArtifactTag')" + "message": "cannot specify spec.serviceAccountName when spec.type is not one of AzureDevOps*, AWSCodeCommit* or *ArtifactTag", + "rule": "!has(self.serviceAccountName) || self.type.startsWith('AzureDevOps') || self.type.startsWith('AWSCodeCommit') || self.type.endsWith('ArtifactTag')" }, { - "message": "cannot specify spec.certSecretRef when spec.type is one of Static, AzureDevOps*, ACRArtifactTag, ECRArtifactTag or GARArtifactTag", - "rule": "!has(self.certSecretRef) || !(self.url == 'Static' || self.type.startsWith('AzureDevOps') || (self.type.endsWith('ArtifactTag') && self.type != 'OCIArtifactTag'))" + "message": "cannot specify spec.certSecretRef when spec.type is one of Static, AzureDevOps*, AWSCodeCommit*, ACRArtifactTag, ECRArtifactTag or GARArtifactTag", + "rule": "!has(self.certSecretRef) || !(self.url == 'Static' || self.type.startsWith('AzureDevOps') || self.type.startsWith('AWSCodeCommit') || (self.type.endsWith('ArtifactTag') && self.type != 'OCIArtifactTag'))" }, { - "message": "cannot specify spec.secretRef when spec.type is one of Static, ACRArtifactTag, ECRArtifactTag or GARArtifactTag", - "rule": "!has(self.secretRef) || !(self.url == 'Static' || (self.type.endsWith('ArtifactTag') && self.type != 'OCIArtifactTag'))" + "message": "cannot specify spec.secretRef when spec.type is one of Static, AWSCodeCommit*, ACRArtifactTag, ECRArtifactTag or GARArtifactTag", + "rule": "!has(self.secretRef) || !(self.url == 'Static' || self.type.startsWith('AWSCodeCommit') || (self.type.endsWith('ArtifactTag') && self.type != 'OCIArtifactTag'))" } - ], - "additionalProperties": false + ] }, "status": { + "additionalProperties": false, "description": "ResourceSetInputProviderStatus defines the observed state of ResourceSetInputProvider.", "properties": { "conditions": { "description": "Conditions contains the readiness conditions of the object.", "items": { + "additionalProperties": false, "description": "Condition contains details for one aspect of the current state of this API Resource.", "properties": { "lastTransitionTime": { @@ -285,8 +294,7 @@ "status", "type" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" }, @@ -314,6 +322,7 @@ "type": "string" }, "nextSchedule": { + "additionalProperties": false, "description": "NextSchedule is the next schedule when the input provider will run.", "properties": { "cron": { @@ -341,13 +350,11 @@ "cron", "when" ], - "type": "object", - "additionalProperties": false + "type": "object" } }, - "type": "object", - "additionalProperties": false + "type": "object" } }, "type": "object" -} \ No newline at end of file +} diff --git a/.agents/skills/gitops-knowledge/evals/evals.json b/.agents/skills/gitops-knowledge/evals/evals.json index 97dbc396a..7f1cbee63 100644 --- a/.agents/skills/gitops-knowledge/evals/evals.json +++ b/.agents/skills/gitops-knowledge/evals/evals.json @@ -84,7 +84,7 @@ { "id": 5, "prompt": "I'm setting up a new production Kubernetes cluster with Flux. I want to use the OCI-based (gitless) GitOps model. My fleet manifests are at oci://ghcr.io/acme-corp/fleet-prod. The cluster should be multi-tenant with medium sizing. I need two ResourceSets: 'infra' for deploying cert-manager and monitoring, and 'apps' for deploying frontend and backend services. The apps ResourceSet should wait for infra to be Ready before deploying. Each component gets its own namespace with an OCIRepository + Kustomization. Generate the FluxInstance and both ResourceSets.", - "expected_output": "A FluxInstance named 'flux' in flux-system with OCI sync, multi-tenancy enabled, medium cluster size. Two ResourceSets using << >> delimiters with dependsOn chain and readyExpr CEL expressions.", + "expected_output": "A FluxInstance named 'flux' in flux-system with OCI sync, multi-tenancy enabled, medium cluster size. Two ResourceSets using << >> delimiters with a dependsOn chain using ready: true.", "files": [], "expectations": [ "The FluxInstance uses apiVersion fluxcd.controlplane.io/v1", @@ -97,7 +97,7 @@ "Both ResourceSets use apiVersion fluxcd.controlplane.io/v1", "Both ResourceSets use << >> template delimiters (not {{ }})", "The apps ResourceSet has spec.dependsOn referencing the infra ResourceSet", - "The dependsOn includes ready: true and a readyExpr with a CEL expression", + "The dependsOn includes ready: true (a readyExpr CEL expression is optional, not required)", "The infra ResourceSet inputs include entries for cert-manager and monitoring", "The apps ResourceSet inputs include entries for frontend and backend", "Generated Kustomizations include spec.prune (required field)" @@ -122,6 +122,26 @@ "The output does NOT use the legacy 'fluxcd/flux' Terraform provider or 'flux bootstrap' CLI", "The Terraform variable holding the GitHub App PEM is marked 'sensitive = true'" ] + }, + { + "id": 7, + "prompt": "Our team wants to adopt Gitless GitOps with Flux. We keep rendered Kubernetes manifests in a GitHub repo at https://github.com/acme-corp/k8s-infra under ./deploy. I need: (1) a GitHub Actions workflow that on push to main and on version tags packages ./deploy as an OCI artifact in ghcr.io, applies our channel tagging conventions (immutable build tags, 'latest' for main, 'latest-stable' for releases), and signs the artifact with keyless Cosign; (2) the Flux CLI command to push the artifact manually with the Git origin metadata embedded; (3) the OCIRepository and Kustomization manifests for the production cluster that pull the 'latest-stable' channel, enforce Cosign signature verification of the GitHub Actions identity, and deploy to the 'apps' namespace.", + "expected_output": "A GitHub Actions workflow with packages:write and id-token:write permissions, using the Flux CLI or the controlplaneio-fluxcd push action and cosign-installer, signing the pushed digest with 'cosign sign --yes'. Tag conventions: immutable build tags plus 'latest' (main) and 'latest-stable' (releases). A 'flux push artifact' command with --path, --source, and --revision in '@sha1:' format. An OCIRepository (source.toolkit.fluxcd.io/v1) with ref.tag latest-stable and verify.provider cosign with matchOIDCIdentity, plus a Kustomization (kustomize.toolkit.fluxcd.io/v1) with prune and targetNamespace apps.", + "files": [], + "expectations": [ + "The GitHub Actions workflow grants 'id-token: write' permission (required for keyless Cosign signing)", + "The GitHub Actions workflow grants 'packages: write' permission (required for pushing to ghcr.io)", + "The workflow uses the controlplaneio-fluxcd/distribution push action", + "The workflow installs Cosign (e.g. sigstore/cosign-installer) and signs the pushed artifact digest with 'cosign sign --yes'", + "The tagging follows the channel conventions: 'latest' for main branch builds and 'latest-stable' for release tags, alongside immutable build tags (commit SHA or version)", + "The manual CLI command is 'flux push artifact oci://...' with a --path flag pointing at the manifests directory", + "The 'flux push artifact' command sets --source with the Git URL and --revision in '@sha1:' format", + "The OCIRepository uses apiVersion source.toolkit.fluxcd.io/v1", + "The OCIRepository url starts with 'oci://' and ref.tag is 'latest-stable'", + "The OCIRepository spec.verify.provider is 'cosign' with matchOIDCIdentity matching the GitHub Actions OIDC issuer (token.actions.githubusercontent.com) and the repo's workflow subject", + "The Kustomization uses apiVersion kustomize.toolkit.fluxcd.io/v1 with sourceRef kind OCIRepository", + "The Kustomization includes spec.prune and targetNamespace 'apps'" + ] } ] } diff --git a/.agents/skills/gitops-knowledge/references/best-practices.md b/.agents/skills/gitops-knowledge/references/best-practices.md index 224b038f5..becc5ac5c 100644 --- a/.agents/skills/gitops-knowledge/references/best-practices.md +++ b/.agents/skills/gitops-knowledge/references/best-practices.md @@ -21,23 +21,24 @@ Prescriptive guidance for production Flux deployments with Flux Operator. is fully rolled out before dependents proceed. - **CRDs before CRs:** Deploy CRD-installing HelmReleases in a separate Kustomization that runs before the Kustomization applying custom resources. -- **ResourceSet dependency chains:** Use `ready: true` with `readyExpr` CEL expressions - for cross-ResourceSet dependencies (policies → infra → apps). +- **ResourceSet dependency chains:** Use `ready: true` for cross-ResourceSet + dependencies (policies → infra → apps). Optionally add a `readyExpr` CEL expression + to replace the built-in readiness check with a custom one. ## Remediation and Reliability - **Install/upgrade strategies:** Always use `RetryOnFailure` — it retries without uninstalling or rolling back, avoiding downtime and data loss on transient failures. - **Set `retryInterval`:** Configure retry intervals on Kustomizations (`retryInterval: 5m`) - and HelmReleases (`strategy.retryInterval: 3m`) for faster recovery from transient failures. + and HelmReleases (`strategy.retryInterval: 5m`) for faster recovery from transient failures. - **Drift detection:** Enable `driftDetection.mode: enabled` on HelmReleases for critical applications to prevent manual cluster changes from diverging. Ignore HPA-managed fields like `/spec/replicas`. - **Timeouts:** Set explicit `timeout` on Kustomizations and HelmReleases to prevent indefinite hanging during apply operations. - **CRD handling:** Use `install.crds: Create` and `upgrade.crds: CreateReplace` for - HelmReleases that manage CRDs. Set `keep: false` for CRDs that should be cleaned up - on uninstall. + HelmReleases that manage CRDs. Note that CRDs installed via a Helm chart are **not** + deleted on uninstall — Helm has no native support for removing CRDs. - **Reactivity:** Add `reconcile.fluxcd.io/watch: Enabled` label to ConfigMaps and Secrets that feed into `postBuild.substituteFrom` or `valuesFrom` — this triggers immediate reconciliation when values change instead of waiting for the next interval. diff --git a/.agents/skills/gitops-knowledge/references/flux-operator.md b/.agents/skills/gitops-knowledge/references/flux-operator.md index f8a7de68e..d16a5887e 100644 --- a/.agents/skills/gitops-knowledge/references/flux-operator.md +++ b/.agents/skills/gitops-knowledge/references/flux-operator.md @@ -146,7 +146,7 @@ Optional components: | `cluster.type` | string | `kubernetes` | `kubernetes`, `openshift`, `aws`, `azure`, `gcp` | | `cluster.size` | string | `medium` | Affects controller resource limits and concurrency | | `cluster.multitenant` | bool | false | Enable multi-tenancy lockdown | -| `cluster.tenantDefaultServiceAccount` | string | — | Default SA for tenant reconcilers | +| `cluster.tenantDefaultServiceAccount` | string | `default` | Default SA for tenant reconcilers when multitenant lockdown is enabled and the field is omitted | | `cluster.networkPolicy` | bool | true | Restrict network access to Flux controllers | | `cluster.domain` | string | `cluster.local` | Kubernetes cluster domain | @@ -280,8 +280,12 @@ spec: Read-only resource reflecting the observed state of the Flux installation. Auto-generated and updated by the operator at regular intervals (default: every 5 minutes). +All report data is stored under `.spec` (not `.status`). The `.status` subresource holds +only reconciliation conditions (the `Ready` condition). Query report data via `.spec.*` +paths — e.g. `.spec.sync.ready`, **not** `.status.sync.ready`. + ```yaml -status: +spec: distribution: version: "2.5.0" status: "Installed" diff --git a/.agents/skills/gitops-knowledge/references/gitless-gitops.md b/.agents/skills/gitops-knowledge/references/gitless-gitops.md new file mode 100644 index 000000000..a5da3d010 --- /dev/null +++ b/.agents/skills/gitops-knowledge/references/gitless-gitops.md @@ -0,0 +1,361 @@ +# Gitless GitOps Reference + +Gitless GitOps keeps Git as the developer source of truth, but removes Git from the +runtime dependency chain. CI packages rendered Kubernetes configuration as OCI artifacts, +pushes them to a container registry, and Flux pulls from the registry using +`OCIRepository`. + +Use this reference when users ask about Flux OCI artifacts, `flux push artifact`, +GitHub Actions publishing, artifact signing, registry-based promotion, or running Flux in +clusters that should not access Git. + +## Why Gitless GitOps + +Traditional GitOps requires production clusters to clone Git repositories. Gitless GitOps +changes the delivery path: + +```text +Git source -> CI build -> OCI registry -> Flux clusters +``` + +Motivation: + +| Concern | Git-based runtime | Gitless runtime | +|---|---|---| +| Cluster network access | Git server and registry | Registry only | +| Credentials in cluster | Git credentials or SSH keys | Registry pull identity | +| Air-gapped operation | Mirror Git or expose Git | Mirror OCI artifacts | +| Integrity | Git commit history | Immutable digest + signature verification | +| Monorepo scale | Cluster clones large repo | CI publishes per-component artifacts | +| Sync speed | Clone/fetch Git | Pull pre-packaged artifact | + +Git still matters: it remains where humans review and merge source changes. The +container registry becomes the deployment source of truth for clusters. + +## Artifact Types + +Flux supports two common OCI artifact shapes: + +| Artifact | Producer | Consumer | +|---|---|---| +| Kubernetes manifests | `flux push artifact` | `OCIRepository` + `Kustomization` | +| Helm charts | Helm chart push or chart CI | `OCIRepository` + `HelmRelease.chartRef` | + +For plain Kubernetes YAML, `flux push artifact` creates OCI artifacts with Flux media +types and stores Git source/revision metadata when `--source` and `--revision` are set. + +For application container images, publish the image and the config artifact in the same CI +pipeline when possible. The config artifact should reference immutable image tags or +digests. For fully Gitless image and chart updates driven by registry tags, use +`ResourceSetInputProvider` with `type: OCIArtifactTag` (see +`references/gitless-image-automation.md`). + +For Helm charts stored in OCI registries, use `OCIRepository` with `layerSelector`: + +```yaml +spec: + layerSelector: + mediaType: "application/vnd.cncf.helm.chart.content.v1.tar+gzip" + operation: copy +``` + +## Publishing Manifests with `flux push artifact` + +Push a directory of rendered manifests using the short Git SHA as the OCI tag: + +```bash +flux push artifact oci://ghcr.io/org/fleet/apps/podinfo:$(git rev-parse --short HEAD) \ + --path="./deploy/production" \ + --source="$(git config --get remote.origin.url)" \ + --revision="$(git branch --show-current)@sha1:$(git rev-parse HEAD)" +``` + +Important flags: + +| Flag | Purpose | +|---|---| +| `--path` | Directory or single YAML file to package | +| `--source` | Original Git URL, stored as OCI metadata | +| `--revision` | Origin revision in `@sha1:` format | +| `--output json` | Prints repository/digest for signing or provenance steps | +| `--provider aws/azure/gcp` | Uses cloud registry authentication | +| `--creds user:password` | Passes generic registry credentials directly | +| `--reproducible` | Produces deterministic digests by fixing the created timestamp | + +Always set `--source` and `--revision`. Flux exposes this metadata in +`OCIRepository.status.artifact.metadata`, `flux trace`, events, notifications, and commit +status integrations. + +### Tagging for Environments + +Push immutable tags, then move environment tags deliberately: + +```bash +IMAGE=oci://ghcr.io/org/fleet/apps/podinfo +SHA_TAG=$(git rev-parse --short HEAD) + +flux push artifact ${IMAGE}:${SHA_TAG} \ + --path="./deploy/staging" \ + --source="$(git config --get remote.origin.url)" \ + --revision="$(git branch --show-current)@sha1:$(git rev-parse HEAD)" + +flux tag artifact ${IMAGE}:${SHA_TAG} --tag latest +``` + +For production releases: + +```bash +TAG=$(git tag --points-at HEAD) + +flux push artifact oci://ghcr.io/org/fleet/apps/podinfo:${TAG} \ + --path="./deploy/production" \ + --source="$(git config --get remote.origin.url)" \ + --revision="${TAG}@sha1:$(git rev-parse HEAD)" + +flux tag artifact oci://ghcr.io/org/fleet/apps/podinfo:${TAG} --tag latest-stable +``` + +Prefer these conventions: + +| Tag | Use | +|---|---| +| Git SHA | Immutable CI build identity | +| Semver tag (`v1.2.3`) | Release identity | +| `latest` | Staging or development channel | +| `latest-stable` | Production channel if promotion is tag-based | +| Semver selector | Production channel if promotion follows version ranges | + +## GitHub Actions Publisher + +Example workflow that packages Kubernetes manifests and signs the OCI artifact with keyless Cosign. + +```yaml +name: publish + +on: + workflow_dispatch: + push: + branches: + - 'main' + tags: + - '*' + +jobs: + flux-push: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write # for pushing + id-token: write # for signing + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Flux CLI + uses: fluxcd/flux2/action@main + - name: Setup cosign + uses: sigstore/cosign-installer@main + - name: Prepare tags + id: prep + run: | + TAG=latest + VERSION="${{ github.ref_name }}-${GITHUB_SHA::8}" + if [[ $GITHUB_REF == refs/tags/* ]]; then + TAG=latest-stable + VERSION="${{ github.ref_name }}" + fi + echo "tag=${TAG}" >> $GITHUB_OUTPUT + echo "version=${VERSION}" >> $GITHUB_OUTPUT + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Push artifact + uses: controlplaneio-fluxcd/distribution/actions/push@main + id: push + with: + repository: ghcr.io/${{ github.repository }} + path: "./" + diff-tag: ${{ steps.prep.outputs.tag }} + tags: ${{ steps.prep.outputs.version }} + - name: Sign artifact + if: steps.push.outputs.pushed == 'true' + run: cosign sign --yes $DIGEST_URL + env: + DIGEST_URL: ${{ steps.push.outputs.digest-url }} +``` + +The artifacts published by this workflow are tagged as: + +- `main-` for the main branch commits. +- `latest` points to the latest artifact tagged as `main-`. +- `vX.Y.Z` for the release tags. +- `latest-stable` points to the latest artifact tagged as `vX.Y.Z`. + +## Consuming Manifest Artifacts + +Use `OCIRepository` as the source and point `Kustomization` at it: + +```yaml +apiVersion: source.toolkit.fluxcd.io/v1 +kind: OCIRepository +metadata: + name: podinfo + namespace: flux-system +spec: + interval: 5m + url: oci://ghcr.io/org/k8s-infra + ref: + tag: latest + verify: + provider: cosign + matchOIDCIdentity: + - issuer: ^https://token\.actions\.githubusercontent\.com$ + subject: ^https://github\.com/org/k8s-infra/\.github/workflows/publish\.yaml@refs/heads/main$ +--- +apiVersion: kustomize.toolkit.fluxcd.io/v1 +kind: Kustomization +metadata: + name: podinfo + namespace: flux-system +spec: + interval: 10m + retryInterval: 2m + sourceRef: + kind: OCIRepository + name: podinfo + path: ./ + prune: true + wait: true + timeout: 5m + targetNamespace: apps +``` + +For production releases, use a semver selector or the promoted channel tag: + +```yaml +spec: + ref: + semver: ">=1.0.0 <2.0.0" +``` + +```yaml +spec: + ref: + tag: latest-stable +``` + +## FluxInstance OCI Sync + +To make the cluster bootstrap itself Gitless, configure `FluxInstance.spec.sync` to use +`OCIRepository`: + +```yaml +spec: + sync: + kind: OCIRepository + url: oci://ghcr.io/org/fleet/clusters + ref: latest-stable + path: clusters/production + pullSecret: ghcr-auth +``` + +The operator creates an `OCIRepository` and a root `Kustomization` named `flux-system`. +For the full FluxInstance spec and the `kustomize.patches` snippet that adds Cosign +signature verification to the generated `OCIRepository`, load `references/flux-operator.md`. + +## Authentication + +For CI publishing: + +- `flux push artifact` reads `~/.docker/config.json`, so Docker login works for GHCR, + Docker Hub, Harbor, and similar registries. +- Use `--creds user:password` for one-off generic credentials. +- Use `--provider aws`, `--provider azure`, or `--provider gcp` for cloud provider + registry auth. + +For cluster pulls: + +```bash +flux create secret oci ghcr-auth \ + --namespace=flux-system \ + --url=ghcr.io \ + --username=flux \ + --password="${GHCR_TOKEN}" +``` + +```yaml +spec: + provider: generic + secretRef: + name: ghcr-auth +``` + +On managed Kubernetes, prefer contextual authorization where possible: + +```yaml +spec: + provider: aws # or azure, gcp + serviceAccountName: flux +``` + +## Signing and Verification + +Keyless Cosign in CI signs with the GitHub Actions OIDC identity. Flux verifies the +signature before storing the artifact: + +```yaml +spec: + verify: + provider: cosign + matchOIDCIdentity: + - issuer: ^https://token\.actions\.githubusercontent\.com$ + subject: ^https://github\.com/org/repo/\.github/workflows/publish\.yaml@refs/heads/main$ +``` + +For release tags, constrain the subject to tag refs: + +```yaml +subject: ^https://github\.com/org/repo/\.github/workflows/publish\.yaml@refs/tags/v\d+\.\d+\.\d+$ +``` + +If verification fails, source-controller marks the `OCIRepository` as not Ready and does +not make the artifact available to downstream `Kustomization` or `HelmRelease` resources. + +## Promotion Patterns + +| Pattern | How it works | Best for | +|--------------------------|--------------------------------------------------------------|--------------------------------| +| Moving channel tag | CI retags immutable build as `latest` or `latest-stable` | Simple staging/prod channels | +| Semver selector | Production `OCIRepository.ref.semver` selects latest release | Release-driven production | +| Digest pin | `ref.digest` points to exact digest | Maximum reproducibility | +| ResourceSetInputProvider | Scans registry tags and templates selected tag/digest | Gitless image/chart automation | + +Do not mutate cluster manifests in Git just to promote OCI artifacts unless a Git audit trail of +promotions is a hard requirement. If Git mutation is required, use +`ImageRepository` + `ImagePolicy` + `ImageUpdateAutomation` instead. + +## Observability and Tracing + +Inspect pulled artifacts: + +```bash +flux get sources oci -A +kubectl -n flux-system describe ocirepository podinfo +``` + +Trace a live workload back to its OCI artifact and Git origin: + +```bash +flux -n apps trace deployment podinfo +``` + +When artifacts are pushed with `--source` and `--revision`, Flux records: + +- `org.opencontainers.image.source` +- `org.opencontainers.image.revision` +- artifact digest and revision + +Configure `Provider` + `Alert` resources to send notifications for `OCIRepository` and +downstream `Kustomization` or `HelmRelease` events. diff --git a/.agents/skills/gitops-knowledge/references/helmrelease.md b/.agents/skills/gitops-knowledge/references/helmrelease.md index efaa1de7a..bb4b9270c 100644 --- a/.agents/skills/gitops-knowledge/references/helmrelease.md +++ b/.agents/skills/gitops-knowledge/references/helmrelease.md @@ -55,6 +55,9 @@ spec: chartRef: kind: OCIRepository name: cert-manager-chart + install: + strategy: + name: RetryOnFailure upgrade: strategy: name: RetryOnFailure @@ -161,7 +164,7 @@ Detects and optionally corrects configuration drift between the Helm release and ```yaml spec: driftDetection: - mode: enabled # enabled or disabled + mode: enabled # disabled (default), warn, or enabled ignore: - paths: - /spec/replicas diff --git a/.agents/skills/gitops-knowledge/references/kustomization.md b/.agents/skills/gitops-knowledge/references/kustomization.md index 2f5b3f87c..18918c64a 100644 --- a/.agents/skills/gitops-knowledge/references/kustomization.md +++ b/.agents/skills/gitops-knowledge/references/kustomization.md @@ -40,13 +40,13 @@ spec: |-------|------|----------|-------------| | `sourceRef.kind` | string | yes | `GitRepository`, `OCIRepository`, `Bucket`, or `ExternalArtifact` | | `sourceRef.name` | string | yes | Source resource name | -| `sourceRef.namespace` | string | no | Cross-namespace reference (disabled by default in multi-tenant) | +| `sourceRef.namespace` | string | no | Cross-namespace reference (enabled by default; platform admins can disable it via the controller `--no-cross-namespace-refs=true` flag) | | `path` | string | no | Path within the source artifact (default: `.`) | | `interval` | duration | yes | Reconciliation interval (e.g., `10m`) | -| `retryInterval` | duration | no | Interval between retries on failure | +| `retryInterval` | duration | no | Interval between retries on failure (defaults to `interval` when unset) | | `prune` | bool | yes | Delete resources removed from the source (garbage collection) | -| `wait` | bool | no | Wait for all resources to become ready (default: false) | -| `timeout` | duration | no | Timeout for the apply operation (default: `5m`) | +| `wait` | bool | no | Wait for all resources to become ready (default: false). When `true`, `.spec.healthChecks` is ignored | +| `timeout` | duration | no | Timeout for apply/health-check/prune operations (defaults to `interval` when unset; no fixed `5m` default) | | `targetNamespace` | string | no | Override namespace for all resources | | `serviceAccountName` | string | no | Service account for impersonation (multi-tenancy) | | `force` | bool | no | Recreate resources that cannot be patched (default: false) | @@ -231,7 +231,7 @@ status: v: v1 ``` -The inventory record format is `___` and `v` is the API version. +The inventory record id format is `___` and `v` is the API version (without group). The inventory enables garbage collection — resources in the inventory but not in the current build are deleted when `prune: true`. diff --git a/.agents/skills/gitops-knowledge/references/notifications.md b/.agents/skills/gitops-knowledge/references/notifications.md index c39165306..aa96ab58d 100644 --- a/.agents/skills/gitops-knowledge/references/notifications.md +++ b/.agents/skills/gitops-knowledge/references/notifications.md @@ -44,7 +44,7 @@ stringData: | `googlechat` | `address` (webhook URL) | — | Google Chat | | `telegram` | `token` | `https://api.telegram.org` | Channel is chat ID | | `matrix` | `token` | Matrix homeserver URL | Channel is room ID | -| `rocketchat` | `address` (webhook URL) | — | | +| `rocket` | `address` (webhook URL) | — | Rocket.Chat (type is `rocket`, not `rocketchat`) | | `lark` | `address` (webhook URL) | — | | | `webex` | `token` | — | Channel is room ID | @@ -57,15 +57,15 @@ stringData: | `sentry` | `address` (DSN) | — | | | `datadog` | `token` (API key) | DataDog endpoint | | | `opsgenie` | `token` (API key) | OpsGenie endpoint | | -| `pagerduty` | `token` (routing key) | — | | +| `pagerduty` | — (none required) | `https://events.pagerduty.com` | Integration routing key set in `spec.channel`, not a secret | **Event streaming:** | Type | Secret Field | Address | Notes | |------|-------------|---------|-------| | `googlepubsub` | `token` (JSON key) | — | Channel is topic ID | -| `azureeventhub` | `address` (connection string) | — | Channel is hub name | -| `nats` | `password` | NATS server URL | Channel is subject | +| `azureeventhub` | `address` (SAS connection string, SAS auth only) | hub name in `spec.address` | `spec.channel` = Event Hubs namespace; `spec.address` = hub name. Managed identity uses `spec.channel`/`spec.address` directly | +| `nats` | `creds` / `nkey` / `username`+`password` (priority order) | NATS server URL | Channel is subject | **Git commit status:** @@ -125,8 +125,7 @@ spec: - kind: OCIRepository name: "*" exclusionList: - - "waiting for" - - "no change" + - "waiting.*socket" ``` ### Key Spec Fields @@ -154,7 +153,7 @@ spec: - kind: HelmRelease name: nginx - # Resources in another namespace + # Resources in another namespace (blocked when multitenant is enabled) - kind: Kustomization name: "*" namespace: apps @@ -230,9 +229,9 @@ stringData: | Field | Type | Required | Description | |-------|------|----------|-------------| -| `type` | string | yes | `github`, `gitlab`, `gitea`, `bitbucket`, `azuredevops`, `generic`, `generic-hmac` | +| `type` | string | yes | `generic`, `generic-hmac`, `github`, `gitlab`, `bitbucket`, `harbor`, `dockerhub`, `quay`, `gcr`, `nexus`, `acr`, `cdevents` (no `gitea`/`azuredevops` Receiver type — Gitea uses the `github` type) | | `events` | array | yes | Event types to accept (e.g., `push`, `ping`, `pull_request`) | -| `secretRef.name` | string | yes | Secret with `token` for HMAC webhook verification | +| `secretRef.name` | string | yes | Secret with `token` for HMAC webhook verification. The Secret should carry the label `reconcile.fluxcd.io/watch: Enabled` so the controller reconciles the Receiver when it changes | | `resources` | array | yes | Resources to trigger reconciliation on | | `suspend` | bool | no | Pause the receiver | diff --git a/.agents/skills/gitops-knowledge/references/repo-patterns.md b/.agents/skills/gitops-knowledge/references/repo-patterns.md index 980e84215..8fc1ae5da 100644 --- a/.agents/skills/gitops-knowledge/references/repo-patterns.md +++ b/.agents/skills/gitops-knowledge/references/repo-patterns.md @@ -43,24 +43,11 @@ fleet/ ### FluxInstance with Git Sync +Configure `FluxInstance.spec.sync` to apply the cluster directory from the fleet repo +(full FluxInstance spec in `references/flux-operator.md`): + ```yaml -apiVersion: fluxcd.controlplane.io/v1 -kind: FluxInstance -metadata: - name: flux - namespace: flux-system spec: - distribution: - version: "2.x" - registry: "ghcr.io/fluxcd" - components: - - source-controller - - kustomize-controller - - helm-controller - - notification-controller - cluster: - type: kubernetes - size: medium sync: kind: GitRepository url: "https://github.com/org/fleet.git" @@ -354,23 +341,11 @@ All patterns use the same approach for cluster-specific configuration: ### Runtime Info ConfigMap -```yaml -apiVersion: v1 -kind: ConfigMap -metadata: - name: flux-runtime-info - namespace: flux-system - labels: - toolkit.fluxcd.io/runtime: "true" - reconcile.fluxcd.io/watch: Enabled - annotations: - kustomize.toolkit.fluxcd.io/ssa: "Merge" -data: - ENVIRONMENT: production # staging, production - CLUSTER_NAME: prod-eu-1 - CLUSTER_DOMAIN: prodeu1.example.com - ARTIFACT_TAG: latest-stable # latest, latest-stable -``` +Each cluster carries a `flux-runtime-info` ConfigMap in `flux-system` with +cluster-specific variables, e.g. `ENVIRONMENT: production`, `CLUSTER_NAME: prod-eu-1`, +`CLUSTER_DOMAIN: prodeu1.example.com`, `ARTIFACT_TAG: latest-stable`. The canonical +manifest — including the `reconcile.fluxcd.io/watch: Enabled` label and the +`kustomize.toolkit.fluxcd.io/ssa: "Merge"` annotation — is in `references/flux-operator.md`. Variables are consumed by: - `postBuild.substituteFrom` in Kustomizations → `${ENVIRONMENT}`, `${CLUSTER_DOMAIN}` diff --git a/.agents/skills/gitops-knowledge/references/resourcesets.md b/.agents/skills/gitops-knowledge/references/resourcesets.md index 203b84a05..729ed23fa 100644 --- a/.agents/skills/gitops-knowledge/references/resourcesets.md +++ b/.agents/skills/gitops-knowledge/references/resourcesets.md @@ -301,14 +301,28 @@ For Secrets, you must also set the `type` field. ### resourcesTemplate -Instead of inline `resources`, reference a ConfigMap containing the template: +Alternative to inline `resources`: a Go template string rendered as multi-document YAML +(documents separated by `---`), useful for `<<- range >>` and `<<- if >>` constructs that +the structured `resources` list cannot express: ```yaml spec: - resourcesTemplate: - name: my-template + inputs: + - tenant: team1 + - tenant: team2 + resourcesTemplate: | + <<- range $input := .inputs >> + --- + apiVersion: v1 + kind: Namespace + metadata: + name: << $input.tenant >> + <<- end >> ``` +When both `resources` and `resourcesTemplate` are set, the generated objects are merged, +with the `resources` entries taking precedence on duplicates. + ### Deduplication When multiple inputs produce resources with the same name/namespace/kind, the last input wins. @@ -320,8 +334,7 @@ Every input entry automatically includes: | Field | Description | |-------|-------------| -| `inputs._index` | Zero-based index of the input entry | -| `inputs._id` | Unique identifier (Adler-32 checksum of input values) | +| `inputs.id` | Unique identifier for the input set amongst all sets generated for the ResourceSet. Value depends on provider type: Adler-32 checksum of the branch/tag name for Git branches, Git tags and OCI tags (checksum of the provider UID for Static), the PR/MR number for pull/merge requests | | `inputs.provider.apiVersion` | API version of the object providing the inputs | | `inputs.provider.kind` | Kind of the object providing the inputs (`ResourceSet` for inline, `ResourceSetInputProvider` for external) | | `inputs.provider.name` | Name of the providing object | diff --git a/.agents/skills/gitops-knowledge/references/sources.md b/.agents/skills/gitops-knowledge/references/sources.md index 5f1d60424..1850a4046 100644 --- a/.agents/skills/gitops-knowledge/references/sources.md +++ b/.agents/skills/gitops-knowledge/references/sources.md @@ -36,19 +36,28 @@ spec: | `ref.tag` | string | Tag name | | `ref.semver` | string | Semver constraint (e.g., `>=1.0.0 <2.0.0`) | | `ref.commit` | string | Exact commit SHA | +| `ref.name` | string | Arbitrary Git reference (e.g., `refs/pull/420/head`, `refs/heads/main`) | | `secretRef.name` | string | Secret with credentials | -| `sparseCheckout` | string | List of directories to checkout with Kubernetes mananifest | +| `provider` | string | Keyless auth provider: `generic` (default), `aws` (CodeCommit IAM), `azure` (Azure DevOps Workload Identity), `github` (GitHub App) | +| `sparseCheckout` | []string | List of directories to checkout when cloning; only the contents of the listed directories appear in the produced artifact | | `recurseSubmodules` | bool | Include Git submodules (default: false) | -| `insecure` | bool | Skip TLS verification for HTTP URLs | -| `verify.secretRef.name` | string | Secret with PGP public keys | +| `verify.mode` | string | Which Git object(s) to verify: `HEAD`, `Tag`, or `TagAndHEAD` | +| `verify.secretRef.name` | string | Secret with PGP public keys (e.g., data keys `author1.asc`) | + +When no `ref` field is set, source-controller checks out the `master` branch. Ref precedence +when multiple are set: `commit` > `name` > `semver` > `tag` > `branch`. There is no +`spec.insecure` field on GitRepository — TLS/CA trust for HTTPS is controlled via the auth +Secret (`ca.crt` for a custom CA, `tls.crt`/`tls.key` for mTLS). **Authentication secrets:** -For HTTPS — Secret with `username` and `password` (or token) fields: +For HTTPS — Secret with `username` and `password` (or token) fields. HTTP bearer-token auth +is also supported via a `bearerToken` data key (instead of `username`/`password`): ```yaml stringData: username: git password: ghp_xxxxxxxxxxxx + # bearerToken: # Alternative to username/password ca.crt: # Optional CA certificate tls.crt: # Optional TLS certificate for mTLS tls.key: # Optional TLS key for mTLS @@ -226,9 +235,10 @@ spec: |-------|------|-------------| | `bucketName` | string | Bucket name | | `endpoint` | string | S3 endpoint (e.g., `s3.amazonaws.com`, `minio.example.com`) | -| `region` | string | AWS region (default: `us-east-1`) | +| `region` | string | Object storage region (optional, no default; some endpoints require it) | | `provider` | string | `generic` (default), `aws`, `azure`, `gcp` | -| `secretRef.name` | string | Secret with `accesskey` and `secretkey` fields | +| `secretRef.name` | string | Secret with credentials. Keys are provider-dependent: `generic`/`aws` use `accesskey`+`secretkey`; `gcp` uses `serviceaccount` (JSON key); `azure` uses Entra ID / `accountKey` / `sasKey` credentials | +| `serviceAccountName` | string | Workload identity for `aws`/`azure`/`gcp` (keyless). Mutually exclusive with `secretRef` | | `certSecretRef.name` | string | Secret with TLS CA and client certs for mTLS auth | | `insecure` | bool | Use HTTP instead of HTTPS | | `prefix` | string | S3 key prefix filter | @@ -247,8 +257,10 @@ metadata: namespace: flux-system ``` -ExternalArtifact has no spec fields to configure — its `status.artifact` is populated by -an external controller (like ArtifactGenerator). Kustomization and HelmRelease can reference +ExternalArtifact has an optional `spec.sourceRef` (with `apiVersion`, `kind`, `name`, and +`namespace` — namespace defaults to the ExternalArtifact's namespace) pointing to the +custom resource the artifact is based on. Its `status.artifact` is populated by an external +controller (like ArtifactGenerator). Kustomization and HelmRelease can reference ExternalArtifact via `sourceRef`. ## ArtifactGenerator diff --git a/.agents/skills/gitops-knowledge/references/terraform-bootstrap.md b/.agents/skills/gitops-knowledge/references/terraform-bootstrap.md index 6fc4444fb..c06b69450 100644 --- a/.agents/skills/gitops-knowledge/references/terraform-bootstrap.md +++ b/.agents/skills/gitops-knowledge/references/terraform-bootstrap.md @@ -218,9 +218,9 @@ Split by authority: `ENVIRONMENT`, `CLUSTER_NAME`. Reconciled by Flux from a `ConfigMap` in `clusters//flux-system/runtime-info.yaml`. -The Git-managed `ConfigMap` must set `kustomize.toolkit.fluxcd.io/ssa: "Merge"` so -kustomize-controller merges its fields instead of replacing the whole `ConfigMap`, -preserving the fields Terraform owns: +The Git-managed `ConfigMap` (the canonical manifest is in `references/flux-operator.md`) +must set `kustomize.toolkit.fluxcd.io/ssa: "Merge"` so kustomize-controller merges its +fields instead of replacing the whole `ConfigMap`, preserving the fields Terraform owns: ```yaml apiVersion: v1 @@ -234,10 +234,10 @@ metadata: annotations: kustomize.toolkit.fluxcd.io/ssa: "Merge" data: + # Git-owned keys only — Terraform-owned keys (CLUSTER_REGION, ACCOUNT_ID, ...) + # are set via managed_resources and never appear here ARTIFACT_TAG: latest ENVIRONMENT: staging - CLUSTER_NAME: staging-1 - CLUSTER_DOMAIN: staging.example.com ``` Because Terraform and kustomize-controller act as different SSA field managers, each diff --git a/.agents/skills/gitops-knowledge/references/web-ui.md b/.agents/skills/gitops-knowledge/references/web-ui.md index f51aa169b..cc6ad2b02 100644 --- a/.agents/skills/gitops-knowledge/references/web-ui.md +++ b/.agents/skills/gitops-knowledge/references/web-ui.md @@ -110,19 +110,28 @@ Default OIDC scopes requested: `openid`, `offline_access`, `profile`, `email`, ` ### SSO Providers -**Dex** — lightweight OIDC provider supporting static users, GitHub, GitLab, LDAP connectors: +**Dex** — lightweight OIDC provider supporting static users, GitHub, GitLab, LDAP connectors. +Supply the client credentials inline (as shown above), or keep them out of the manifest using +a Kubernetes Secret with **hyphenated** keys consumed through the HelmRelease `valuesFrom` + +`targetPath`: ```yaml -# Create Secret with OIDC credentials -apiVersion: v1 -kind: Secret -metadata: - name: flux-web-oidc - namespace: flux-system -stringData: - clientID: flux-web - clientSecret: flux-web-secret - issuerURL: https://dex.example.com +# Create the Secret with: kubectl -n flux-system create secret generic flux-web-client \ +# --from-literal=client-id=flux-web --from-literal=client-secret= +# Then map its keys onto the web config in the Flux Operator HelmRelease: +valuesFrom: + - kind: Secret + name: flux-web-client + valuesKey: client-id + targetPath: web.config.authentication.oauth2.clientID + - kind: Secret + name: flux-web-client + valuesKey: client-secret + targetPath: web.config.authentication.oauth2.clientSecret ``` +Alternatively, reference an existing Secret via `web.configSecretName`, where the Secret holds a +`config.yaml` key containing the full Web Config spec (`apiVersion: web.fluxcd.controlplane.io/v1`, +`kind: Config`). There is no Secret read directly by the UI with camelCase `clientID`/`clientSecret` +keys. **Keycloak** — create an OpenID Connect client in Keycloak admin console with Standard flow enabled and redirect URI set to `https://flux.example.com/callback`. @@ -132,7 +141,11 @@ Standard flow enabled and redirect URI set to `https://flux.example.com/callback issuerURL: https://login.microsoftonline.com//v2.0 ``` -**OpenShift** — configure via OLM Subscription with `WEB_CONFIG_SECRET_NAME` environment variable. +With the Flux Operator Helm chart, the authentication config is supplied either inline via the +`web.config` Helm value (the Web Config spec) or via `web.configSecretName`, which references an +existing Secret in the deployment namespace containing a `config.yaml` key. With OLM/OpenShift +installations, set the `WEB_CONFIG_SECRET_NAME` environment variable in the Subscription +`config.env` to point the operator at the same kind of Secret. ### Claims Mapping and CEL Expressions diff --git a/.agents/skills/gitops-repo-audit/SKILL.md b/.agents/skills/gitops-repo-audit/SKILL.md index c47135c3f..8e1677023 100644 --- a/.agents/skills/gitops-repo-audit/SKILL.md +++ b/.agents/skills/gitops-repo-audit/SKILL.md @@ -5,9 +5,9 @@ description: | license: Apache-2.0 metadata: github-path: skills/gitops-repo-audit - github-ref: refs/tags/v0.0.3 + github-ref: refs/tags/v0.0.4 github-repo: https://github.com/fluxcd/agent-skills - github-tree-sha: 6a0bce48f3bda341fce4ad2c4c798b40b40b98c4 + github-tree-sha: f1974c94903b38c0756041d9ee9bf84cdfb997f6 name: gitops-repo-audit --- # GitOps Repository Auditor diff --git a/.agents/skills/gitops-repo-audit/assets/schemas/fluxinstance-fluxcd-v1.json b/.agents/skills/gitops-repo-audit/assets/schemas/fluxinstance-fluxcd-v1.json index 1f6e9a51d..1635135e4 100644 --- a/.agents/skills/gitops-repo-audit/assets/schemas/fluxinstance-fluxcd-v1.json +++ b/.agents/skills/gitops-repo-audit/assets/schemas/fluxinstance-fluxcd-v1.json @@ -13,9 +13,11 @@ "type": "object" }, "spec": { + "additionalProperties": false, "description": "FluxInstanceSpec defines the desired state of FluxInstance", "properties": { "cluster": { + "additionalProperties": false, "description": "Cluster holds the specification of the Kubernetes cluster.", "properties": { "domain": { @@ -82,10 +84,10 @@ "message": ".objectLevelWorkloadIdentity must be set to true when .multitenantWorkloadIdentity is set to true", "rule": "(has(self.objectLevelWorkloadIdentity) && self.objectLevelWorkloadIdentity) || !has(self.multitenantWorkloadIdentity) || !self.multitenantWorkloadIdentity" } - ], - "additionalProperties": false + ] }, "commonMetadata": { + "additionalProperties": false, "description": "CommonMetadata specifies the common labels and annotations that are\napplied to all resources. Any existing label or annotation will be\noverridden if its key matches a common one.", "properties": { "annotations": { @@ -103,8 +105,7 @@ "type": "object" } }, - "type": "object", - "additionalProperties": false + "type": "object" }, "components": { "description": "Components is the list of controllers to install.\nDefaults to the core Flux controllers:\n - source-controller\n - kustomize-controller\n - helm-controller\n - notification-controller", @@ -124,6 +125,7 @@ "type": "array" }, "distribution": { + "additionalProperties": false, "description": "Distribution specifies the version and container registry to pull images from.", "properties": { "artifact": { @@ -162,15 +164,16 @@ "registry", "version" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "kustomize": { + "additionalProperties": false, "description": "Kustomize holds a set of patches that can be applied to the\nFlux installation, to customize the way Flux operates.", "properties": { "patches": { "description": "Strategic merge and JSON patches, defined as inline YAML objects,\ncapable of targeting objects based on kind, label and annotation selectors.", "items": { + "additionalProperties": false, "description": "Patch contains an inline StrategicMerge or JSON6902 patch, and the target the patch should\nbe applied to.", "properties": { "patch": { @@ -178,6 +181,7 @@ "type": "string" }, "target": { + "additionalProperties": false, "description": "Target points to the resources that the patch document should be applied to.", "properties": { "annotationSelector": { @@ -209,21 +213,18 @@ "type": "string" } }, - "type": "object", - "additionalProperties": false + "type": "object" } }, "required": [ "patch" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" } }, - "type": "object", - "additionalProperties": false + "type": "object" }, "migrateResources": { "default": true, @@ -231,6 +232,7 @@ "type": "boolean" }, "sharding": { + "additionalProperties": false, "description": "Sharding holds the specification of the sharding configuration.", "properties": { "key": { @@ -258,10 +260,10 @@ "required": [ "shards" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "storage": { + "additionalProperties": false, "description": "Storage holds the specification of the source-controller\npersistent volume claim.", "properties": { "class": { @@ -277,10 +279,10 @@ "class", "size" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "sync": { + "additionalProperties": false, "description": "Sync specifies the source for the cluster sync operation.\nWhen set, a Flux source (GitRepository, OCIRepository or Bucket)\nand Flux Kustomization are created to sync the cluster state\nwith the source repository.", "properties": { "interval": { @@ -314,7 +316,7 @@ "type": "string" }, "provider": { - "description": "Provider specifies OIDC provider for source authentication.\nFor OCIRepository and Bucket the provider can be set to 'aws', 'azure' or 'gcp'.\nfor GitRepository the accepted value can be set to 'azure' or 'github'.\nTo disable OIDC authentication the provider can be set to 'generic' or left empty.", + "description": "Provider specifies OIDC provider for source authentication.\nFor OCIRepository and Bucket the provider can be set to 'aws', 'azure' or 'gcp'.\nFor GitRepository the provider can be set to 'aws' (requires Flux 2.9 or later),\n'azure' or 'github'.\nTo disable OIDC authentication the provider can be set to 'generic' or left empty.", "enum": [ "generic", "aws", @@ -344,7 +346,16 @@ "url" ], "type": "object", - "additionalProperties": false + "x-kubernetes-validations": [ + { + "message": "sync.provider 'gcp' is only supported for OCIRepository and Bucket", + "rule": "!has(self.provider) || self.provider != 'gcp' || self.kind == 'OCIRepository' || self.kind == 'Bucket'" + }, + { + "message": "sync.provider 'github' is only supported for GitRepository", + "rule": "!has(self.provider) || self.provider != 'github' || self.kind == 'GitRepository'" + } + ] }, "wait": { "default": true, @@ -355,15 +366,16 @@ "required": [ "distribution" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "status": { + "additionalProperties": false, "description": "FluxInstanceStatus defines the observed state of FluxInstance", "properties": { "components": { "description": "Components contains the container images used by the components.", "items": { + "additionalProperties": false, "description": "ComponentImage represents a container image used by a component.", "properties": { "digest": { @@ -388,14 +400,14 @@ "repository", "tag" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" }, "conditions": { "description": "Conditions contains the readiness conditions of the object.", "items": { + "additionalProperties": false, "description": "Condition contains details for one aspect of the current state of this API Resource.", "properties": { "lastTransitionTime": { @@ -444,14 +456,14 @@ "status", "type" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" }, "history": { "description": "History contains the reconciliation history of the FluxInstance\nas a list of snapshots ordered by the last reconciled time.", "items": { + "additionalProperties": false, "description": "Snapshot represents a point-in-time record of a group of resources reconciliation,\nincluding timing information, status, and a unique digest identifier.", "properties": { "digest": { @@ -497,17 +509,18 @@ "lastReconciledStatus", "totalReconciliations" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" }, "inventory": { + "additionalProperties": false, "description": "Inventory contains a list of Kubernetes resource object references\nlast applied on the cluster.", "properties": { "entries": { "description": "Entries of Kubernetes resource object references.", "items": { + "additionalProperties": false, "description": "ResourceRef contains the information necessary to locate a resource within a cluster.", "properties": { "id": { @@ -523,8 +536,7 @@ "id", "v" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" } @@ -532,8 +544,7 @@ "required": [ "entries" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "lastAppliedRevision": { "description": "LastAppliedRevision is the version and digest of the\ndistribution config that was last reconcile.", @@ -556,8 +567,7 @@ "type": "string" } }, - "type": "object", - "additionalProperties": false + "type": "object" } }, "type": "object", @@ -567,4 +577,4 @@ "rule": "self.metadata.name == 'flux'" } ] -} \ No newline at end of file +} diff --git a/.agents/skills/gitops-repo-audit/assets/schemas/fluxreport-fluxcd-v1.json b/.agents/skills/gitops-repo-audit/assets/schemas/fluxreport-fluxcd-v1.json index a7f6fc861..e7b9876d4 100644 --- a/.agents/skills/gitops-repo-audit/assets/schemas/fluxreport-fluxcd-v1.json +++ b/.agents/skills/gitops-repo-audit/assets/schemas/fluxreport-fluxcd-v1.json @@ -13,9 +13,11 @@ "type": "object" }, "spec": { + "additionalProperties": false, "description": "FluxReportSpec defines the observed state of a Flux installation.", "properties": { "cluster": { + "additionalProperties": false, "description": "Cluster is the version information of the Kubernetes cluster.", "properties": { "nodes": { @@ -35,12 +37,12 @@ "platform", "serverVersion" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "components": { "description": "ComponentsStatus is the status of the Flux controller deployments.", "items": { + "additionalProperties": false, "description": "FluxComponentStatus defines the observed state of a Flux component.", "properties": { "image": { @@ -66,12 +68,12 @@ "ready", "status" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" }, "distribution": { + "additionalProperties": false, "description": "Distribution is the version information of the Flux installation.", "properties": { "entitlement": { @@ -95,10 +97,10 @@ "entitlement", "status" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "operator": { + "additionalProperties": false, "description": "Operator is the version information of the Flux Operator.", "properties": { "apiVersion": { @@ -119,12 +121,12 @@ "platform", "version" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "reconcilers": { "description": "ReconcilersStatus is the list of Flux reconcilers and\ntheir statistics grouped by API kind.", "items": { + "additionalProperties": false, "description": "FluxReconcilerStatus defines the observed state of a Flux reconciler.", "properties": { "apiVersion": { @@ -136,6 +138,7 @@ "type": "string" }, "stats": { + "additionalProperties": false, "description": "Stats is the reconcile statics of the Flux resource kind.", "properties": { "failing": { @@ -160,20 +163,19 @@ "running", "suspended" ], - "type": "object", - "additionalProperties": false + "type": "object" } }, "required": [ "apiVersion", "kind" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" }, "sync": { + "additionalProperties": false, "description": "SyncStatus is the status of the cluster sync\nSource and Kustomization resources.", "properties": { "id": { @@ -202,22 +204,22 @@ "ready", "status" ], - "type": "object", - "additionalProperties": false + "type": "object" } }, "required": [ "distribution" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "status": { + "additionalProperties": false, "description": "FluxReportStatus defines the readiness of a FluxReport.", "properties": { "conditions": { "description": "Conditions contains the readiness conditions of the object.", "items": { + "additionalProperties": false, "description": "Condition contains details for one aspect of the current state of this API Resource.", "properties": { "lastTransitionTime": { @@ -266,8 +268,7 @@ "status", "type" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" }, @@ -276,8 +277,7 @@ "type": "string" } }, - "type": "object", - "additionalProperties": false + "type": "object" } }, "type": "object", @@ -287,4 +287,4 @@ "rule": "self.metadata.name == 'flux'" } ] -} \ No newline at end of file +} diff --git a/.agents/skills/gitops-repo-audit/assets/schemas/helmrelease-helm-v2.json b/.agents/skills/gitops-repo-audit/assets/schemas/helmrelease-helm-v2.json index 885e724e1..5cd8695c1 100644 --- a/.agents/skills/gitops-repo-audit/assets/schemas/helmrelease-helm-v2.json +++ b/.agents/skills/gitops-repo-audit/assets/schemas/helmrelease-helm-v2.json @@ -651,7 +651,7 @@ "type": "boolean" }, "force": { - "description": "Force forces resource updates through a replacement strategy.", + "description": "Force forces resource updates through a replacement strategy\nthat avoids 3-way merge conflicts on client-side apply.\nThis field is ignored for server-side apply (which always\nforces conflicts with other field managers).", "type": "boolean" }, "recreate": { @@ -822,7 +822,7 @@ "type": "boolean" }, "force": { - "description": "Force forces resource updates through a replacement strategy.", + "description": "Force forces resource updates through a replacement strategy\nthat avoids 3-way merge conflicts on client-side apply.\nThis field is ignored for server-side apply (which always\nforces conflicts with other field managers).", "type": "boolean" }, "preserveValues": { diff --git a/.agents/skills/gitops-repo-audit/assets/schemas/receiver-notification-v1.json b/.agents/skills/gitops-repo-audit/assets/schemas/receiver-notification-v1.json index ea548e1a5..90141f3a4 100644 --- a/.agents/skills/gitops-repo-audit/assets/schemas/receiver-notification-v1.json +++ b/.agents/skills/gitops-repo-audit/assets/schemas/receiver-notification-v1.json @@ -89,7 +89,7 @@ "type": "array" }, "secretRef": { - "description": "SecretRef specifies the Secret containing the token used\nto validate the payload authenticity. The Secret must contain a 'token'\nkey. For GCR receivers, the Secret must also contain an 'email' key\nwith the IAM service account email configured on the Pub/Sub push\nsubscription, and may optionally contain an 'audience' key with the\nexpected OIDC token audience.", + "description": "SecretRef specifies the Secret containing the token used\nto validate the payload authenticity. The Secret must contain a 'token'\nkey. For GCR receivers, the Secret must also contain an 'email' key\nwith the IAM service account email configured on the Pub/Sub push\nsubscription, and an 'audience' key with the expected OIDC token audience.", "properties": { "name": { "description": "Name of the referent.", diff --git a/.agents/skills/gitops-repo-audit/assets/schemas/resourceset-fluxcd-v1.json b/.agents/skills/gitops-repo-audit/assets/schemas/resourceset-fluxcd-v1.json index 8dd944ce3..f55e30eea 100644 --- a/.agents/skills/gitops-repo-audit/assets/schemas/resourceset-fluxcd-v1.json +++ b/.agents/skills/gitops-repo-audit/assets/schemas/resourceset-fluxcd-v1.json @@ -13,9 +13,11 @@ "type": "object" }, "spec": { + "additionalProperties": false, "description": "ResourceSetSpec defines the desired state of ResourceSet", "properties": { "commonMetadata": { + "additionalProperties": false, "description": "CommonMetadata specifies the common labels and annotations that are\napplied to all resources. Any existing label or annotation will be\noverridden if its key matches a common one.", "properties": { "annotations": { @@ -33,12 +35,12 @@ "type": "object" } }, - "type": "object", - "additionalProperties": false + "type": "object" }, "dependsOn": { "description": "DependsOn specifies the list of Kubernetes resources that must\nexist on the cluster before the reconciliation process starts.", "items": { + "additionalProperties": false, "description": "Dependency defines a ResourceSet dependency on a Kubernetes resource.", "properties": { "apiVersion": { @@ -71,14 +73,18 @@ "kind", "name" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" }, "inputStrategy": { + "additionalProperties": false, "description": "InputStrategy defines how the inputs are combined when multiple\ninput provider objects are used. Defaults to flattening all inputs\nfrom all providers into a single list of input sets.", "properties": { + "includeEmptyProviders": { + "description": "IncludeEmptyProviders controls how input providers that export no\ninputs are treated. Only applies when Name is Permute. When true, if\nany provider has zero inputs the resulting permutation set is empty\n(mathematically correct Cartesian product behavior). When false or\nunset (default), providers with zero inputs are silently skipped and\nthe remaining providers still permute among themselves.", + "type": "boolean" + }, "name": { "description": "Name defines how the inputs are combined when multiple\ninput provider objects are used. Supported values are:\n- Flatten: all inputs sets from all input provider objects are\n flattened into a single list of input sets.\n- Permute: all inputs sets from all input provider objects are\n combined using a Cartesian product, resulting in a list of input sets\n that contains every possible combination of input values.\n For example, if provider A has inputs [{x: 1}, {x: 2}] and provider B has\n inputs [{y: \"a\"}, {y: \"b\"}], the resulting input sets will be:\n [{x: 1, y: \"a\"}, {x: 1, y: \"b\"}, {x: 2, y: \"a\"}, {x: 2, y: \"b\"}].\n This strategy can lead to a large number of input sets and should be\n used with caution. Users should use filtering features from\n ResourceSetInputProvider to limit the amount of exported inputs.", "enum": [ @@ -92,7 +98,12 @@ "name" ], "type": "object", - "additionalProperties": false + "x-kubernetes-validations": [ + { + "message": "includeEmptyProviders only applies when name is Permute", + "rule": "!has(self.includeEmptyProviders) || self.name == 'Permute'" + } + ] }, "inputs": { "description": "Inputs contains the list of ResourceSet inputs.", @@ -108,6 +119,7 @@ "inputsFrom": { "description": "InputsFrom contains the list of references to input providers.\nWhen set, the inputs are fetched from the providers and concatenated\nwith the in-line inputs defined in the ResourceSet.", "items": { + "additionalProperties": false, "description": "InputProviderReference defines a reference to an input provider resource\nin the same namespace as the ResourceSet.", "properties": { "apiVersion": { @@ -129,11 +141,13 @@ "type": "string" }, "selector": { + "additionalProperties": false, "description": "Selector is a label selector to filter the input provider resources\nas an alternative to the Name field.", "properties": { "matchExpressions": { "description": "matchExpressions is a list of label selector requirements. The requirements are ANDed.", "items": { + "additionalProperties": false, "description": "A label selector requirement is a selector that contains values, a key, and an operator that\nrelates the key and values.", "properties": { "key": { @@ -157,8 +171,7 @@ "key", "operator" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array", "x-kubernetes-list-type": "atomic" @@ -172,8 +185,7 @@ } }, "type": "object", - "x-kubernetes-map-type": "atomic", - "additionalProperties": false + "x-kubernetes-map-type": "atomic" } }, "type": "object", @@ -186,8 +198,7 @@ "message": "cannot set both name and selector for input provider references", "rule": "!has(self.name) || !has(self.selector)" } - ], - "additionalProperties": false + ] }, "type": "array" }, @@ -211,15 +222,16 @@ "type": "boolean" } }, - "type": "object", - "additionalProperties": false + "type": "object" }, "status": { + "additionalProperties": false, "description": "ResourceSetStatus defines the observed state of ResourceSet.", "properties": { "conditions": { "description": "Conditions contains the readiness conditions of the object.", "items": { + "additionalProperties": false, "description": "Condition contains details for one aspect of the current state of this API Resource.", "properties": { "lastTransitionTime": { @@ -268,14 +280,21 @@ "status", "type" ], - "type": "object", - "additionalProperties": false + "type": "object" + }, + "type": "array" + }, + "externalChecksumRefs": { + "description": "ExternalChecksumRefs lists the ConfigMap and Secret references\ndiscovered in checksumFrom annotations on the last reconciliation\nthat point to objects not rendered by this ResourceSet. Each entry\nhas the form \"Kind/namespace/name\". It is used to trigger a\nreconciliation when one of the referenced objects changes.", + "items": { + "type": "string" }, "type": "array" }, "history": { "description": "History contains the reconciliation history of the ResourceSet\nas a list of snapshots ordered by the last reconciled time.", "items": { + "additionalProperties": false, "description": "Snapshot represents a point-in-time record of a group of resources reconciliation,\nincluding timing information, status, and a unique digest identifier.", "properties": { "digest": { @@ -321,17 +340,18 @@ "lastReconciledStatus", "totalReconciliations" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" }, "inventory": { + "additionalProperties": false, "description": "Inventory contains a list of Kubernetes resource object references\nlast applied on the cluster.", "properties": { "entries": { "description": "Entries of Kubernetes resource object references.", "items": { + "additionalProperties": false, "description": "ResourceRef contains the information necessary to locate a resource within a cluster.", "properties": { "id": { @@ -347,8 +367,7 @@ "id", "v" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" } @@ -356,8 +375,7 @@ "required": [ "entries" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "lastAppliedRevision": { "description": "LastAppliedRevision is the digest of the\ngenerated resources that were last reconcile.", @@ -368,9 +386,8 @@ "type": "string" } }, - "type": "object", - "additionalProperties": false + "type": "object" } }, "type": "object" -} \ No newline at end of file +} diff --git a/.agents/skills/gitops-repo-audit/assets/schemas/resourcesetinputprovider-fluxcd-v1.json b/.agents/skills/gitops-repo-audit/assets/schemas/resourcesetinputprovider-fluxcd-v1.json index 872ca7a8d..5e98e35dc 100644 --- a/.agents/skills/gitops-repo-audit/assets/schemas/resourcesetinputprovider-fluxcd-v1.json +++ b/.agents/skills/gitops-repo-audit/assets/schemas/resourcesetinputprovider-fluxcd-v1.json @@ -13,9 +13,11 @@ "type": "object" }, "spec": { + "additionalProperties": false, "description": "ResourceSetInputProviderSpec defines the desired state of ResourceSetInputProvider", "properties": { "certSecretRef": { + "additionalProperties": false, "description": "CertSecretRef specifies the Kubernetes Secret containing either or both of\n\n- a PEM-encoded CA certificate (`ca.crt`)\n- a PEM-encoded client certificate (`tls.crt`) and private key (`tls.key`)\n\nWhen connecting to a Git, OCI, or ExternalService provider that uses self-signed certificates,\nthe CA certificate must be set in the Secret under the 'ca.crt' key to establish the trust relationship.\nWhen connecting to a provider that supports client certificates (mTLS), the client certificate\nand private key must be set in the Secret under the 'tls.crt' and 'tls.key' keys, respectively.", "properties": { "name": { @@ -26,8 +28,7 @@ "required": [ "name" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "defaultValues": { "additionalProperties": { @@ -37,6 +38,7 @@ "type": "object" }, "filter": { + "additionalProperties": false, "description": "Filter defines the filter to apply to the input provider response.", "properties": { "excludeBranch": { @@ -80,8 +82,7 @@ "type": "string" } }, - "type": "object", - "additionalProperties": false + "type": "object" }, "insecure": { "description": "Insecure allows connecting to an ExternalService or OCIArtifactTag provider\nover plain HTTP without TLS. When not set, the URL must use HTTPS.", @@ -90,6 +91,7 @@ "schedule": { "description": "Schedule defines the schedules for the input provider to run.", "items": { + "additionalProperties": false, "description": "Schedule defines a schedule for something to run.", "properties": { "cron": { @@ -111,12 +113,12 @@ "required": [ "cron" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" }, "secretRef": { + "additionalProperties": false, "description": "SecretRef specifies the Kubernetes Secret containing the credentials\nto access the input provider.\nWhen connecting to a Git provider, the secret must contain the keys\n'username' and 'password', and the password should be a personal access token\nthat grants read-only access to the repository.\nWhen connecting to an OCI provider, the secret must contain a Kubernetes\nImage Pull Secret, as if created by `kubectl create secret docker-registry`.\nWhen connecting to an ExternalService provider, the secret must contain either\na 'token' key for bearer token authentication, or 'username' and 'password'\nkeys for basic authentication.", "properties": { "name": { @@ -127,14 +129,14 @@ "required": [ "name" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "serviceAccountName": { "description": "ServiceAccountName specifies the name of the Kubernetes ServiceAccount\nused for authentication with AWS, Azure or GCP services through\nworkload identity federation features. If not specified, the\nauthentication for these cloud providers will use the ServiceAccount\nof the operator (or any other environment authentication configuration).", "type": "string" }, "skip": { + "additionalProperties": false, "description": "Skip defines whether we need to skip input provider response updates.", "properties": { "labels": { @@ -145,8 +147,7 @@ "type": "array" } }, - "type": "object", - "additionalProperties": false + "type": "object" }, "type": { "description": "Type specifies the type of the input provider.", @@ -162,6 +163,9 @@ "AzureDevOpsBranch", "AzureDevOpsTag", "AzureDevOpsPullRequest", + "AWSCodeCommitBranch", + "AWSCodeCommitTag", + "AWSCodeCommitPullRequest", "GiteaBranch", "GiteaTag", "GiteaPullRequest", @@ -197,8 +201,12 @@ "rule": "!self.type.startsWith('Git') || self.url.startsWith('http')" }, { - "message": "spec.url must start with 'http://' or 'https://' when spec.type is a Git provider", - "rule": "!self.type.startsWith('AzureDevOps') || self.url.startsWith('http')" + "message": "spec.url must start with 'http://' or 'https://' when spec.type is an AzureDevOps provider", + "rule": "!self.type.startsWith('AzureDevOps') || self.url.startsWith('http://') || self.url.startsWith('https://')" + }, + { + "message": "spec.url must start with 'https://' when spec.type is a AWSCodeCommit provider", + "rule": "!self.type.startsWith('AWSCodeCommit') || self.url.startsWith('https://')" }, { "message": "spec.url must start with 'oci://' when spec.type is an OCI provider", @@ -217,26 +225,27 @@ "rule": "self.type != 'ExternalService' || !self.url.startsWith('http://') || (has(self.insecure) && self.insecure)" }, { - "message": "cannot specify spec.serviceAccountName when spec.type is not one of AzureDevOps* or *ArtifactTag", - "rule": "!has(self.serviceAccountName) || self.type.startsWith('AzureDevOps') || self.type.endsWith('ArtifactTag')" + "message": "cannot specify spec.serviceAccountName when spec.type is not one of AzureDevOps*, AWSCodeCommit* or *ArtifactTag", + "rule": "!has(self.serviceAccountName) || self.type.startsWith('AzureDevOps') || self.type.startsWith('AWSCodeCommit') || self.type.endsWith('ArtifactTag')" }, { - "message": "cannot specify spec.certSecretRef when spec.type is one of Static, AzureDevOps*, ACRArtifactTag, ECRArtifactTag or GARArtifactTag", - "rule": "!has(self.certSecretRef) || !(self.url == 'Static' || self.type.startsWith('AzureDevOps') || (self.type.endsWith('ArtifactTag') && self.type != 'OCIArtifactTag'))" + "message": "cannot specify spec.certSecretRef when spec.type is one of Static, AzureDevOps*, AWSCodeCommit*, ACRArtifactTag, ECRArtifactTag or GARArtifactTag", + "rule": "!has(self.certSecretRef) || !(self.url == 'Static' || self.type.startsWith('AzureDevOps') || self.type.startsWith('AWSCodeCommit') || (self.type.endsWith('ArtifactTag') && self.type != 'OCIArtifactTag'))" }, { - "message": "cannot specify spec.secretRef when spec.type is one of Static, ACRArtifactTag, ECRArtifactTag or GARArtifactTag", - "rule": "!has(self.secretRef) || !(self.url == 'Static' || (self.type.endsWith('ArtifactTag') && self.type != 'OCIArtifactTag'))" + "message": "cannot specify spec.secretRef when spec.type is one of Static, AWSCodeCommit*, ACRArtifactTag, ECRArtifactTag or GARArtifactTag", + "rule": "!has(self.secretRef) || !(self.url == 'Static' || self.type.startsWith('AWSCodeCommit') || (self.type.endsWith('ArtifactTag') && self.type != 'OCIArtifactTag'))" } - ], - "additionalProperties": false + ] }, "status": { + "additionalProperties": false, "description": "ResourceSetInputProviderStatus defines the observed state of ResourceSetInputProvider.", "properties": { "conditions": { "description": "Conditions contains the readiness conditions of the object.", "items": { + "additionalProperties": false, "description": "Condition contains details for one aspect of the current state of this API Resource.", "properties": { "lastTransitionTime": { @@ -285,8 +294,7 @@ "status", "type" ], - "type": "object", - "additionalProperties": false + "type": "object" }, "type": "array" }, @@ -314,6 +322,7 @@ "type": "string" }, "nextSchedule": { + "additionalProperties": false, "description": "NextSchedule is the next schedule when the input provider will run.", "properties": { "cron": { @@ -341,13 +350,11 @@ "cron", "when" ], - "type": "object", - "additionalProperties": false + "type": "object" } }, - "type": "object", - "additionalProperties": false + "type": "object" } }, "type": "object" -} \ No newline at end of file +}