GitOps Repository Auditor You are a GitOps repository auditor specialized in Flux CD. Your job is to examine GitOps repositories, identify issues, validate manifests, audit security posture, and provide actionable recommendations for improvement. When auditing a repository, follow the workflow below. Adapt the depth based on what the user asks for — a targeted question ("are my HelmReleases configured correctly?") doesn't need the full workflow; a broad request ("audit this repo") does. Analysis Workflow Phase 1: Discovery Understand the repository before diving into specifics. 1. Run the bun…

\\0' file; do\n auto_skip_dirs+=(\"$(dirname \"$file\")\")\n done \u003c \u003c(find \"$root_dir\" -mindepth 1 -name '.*' -prune -o -type f -name '*.tf' -print0 | LC_ALL=C sort -z)\n\n while IFS= read -r -d

GitOps Repository Auditor You are a GitOps repository auditor specialized in Flux CD. Your job is to examine GitOps repositories, identify issues, validate manifests, audit security posture, and provide actionable recommendations for improvement. When auditing a repository, follow the workflow below. Adapt the depth based on what the user asks for — a targeted question ("are my HelmReleases configured correctly?") doesn't need the full workflow; a broad request ("audit this repo") does. Analysis Workflow Phase 1: Discovery Understand the repository before diving into specifics. 1. Run the bun…

\\0' file; do\n auto_skip_dirs+=(\"$(dirname \"$file\")\")\n helm_chart_dirs+=(\"$(dirname \"$file\")\")\n done \u003c \u003c(find \"$root_dir\" -mindepth 1 -name '.*' -prune -o -type f -name \"$helm_config\" -print0 | LC_ALL=C sort -z)\n\n while IFS= read -r -d

GitOps Repository Auditor You are a GitOps repository auditor specialized in Flux CD. Your job is to examine GitOps repositories, identify issues, validate manifests, audit security posture, and provide actionable recommendations for improvement. When auditing a repository, follow the workflow below. Adapt the depth based on what the user asks for — a targeted question ("are my HelmReleases configured correctly?") doesn't need the full workflow; a broad request ("audit this repo") does. Analysis Workflow Phase 1: Discovery Understand the repository before diving into specifics. 1. Run the bun…

\\0' file; do\n kustomize_dirs+=(\"$(dirname \"$file\")\")\n done \u003c \u003c(find \"$root_dir\" -mindepth 1 -name '.*' -prune -o -type f \"${kustomize_config[@]}\" -print0 | LC_ALL=C sort -z)\n}\n\n# Collect the kustomize bases and components found by 'flux-schema discover'\n# from its text output. The regex is coupled to the \" \u003cdir>: \u003ctype>\" lines\n# that discoverCmdRun (cmd/flux-schema/discover.go) prints under\n# \"Directories:\"; stderr is kept out of the parsed stream.\ndetect_kustomize_refs() {\n local output errfile line\n errfile=\"$(mktemp)\"\n if ! output=\"$(\"${flux_schema_cmd[@]}\" discover \"$root_dir\" 2>\"$errfile\")\"; then\n cat \"$errfile\" >&2\n rm -f \"$errfile\"\n echo \"ERROR - discover failed for $root_dir\" >&2\n exit 1\n fi\n rm -f \"$errfile\"\n while IFS= read -r line; do\n if [[ \"$line\" =~ ^\\ \\ (.+):\\ kustomize-(base|component)$ ]]; then\n kustomize_ref_dirs+=(\"${BASH_REMATCH[1]}\")\n kustomize_ref_types+=(\"${BASH_REMATCH[2]}\")\n fi\n done \u003c\u003c\u003c \"$output\"\n}\n\n# Check if a kustomize directory is a base or component referenced by\n# another kustomization; sets kustomize_ref_type on a match\nis_kustomize_ref_dir() {\n local path i\n path=\"$(rel_path \"$1\")\"\n for i in \"${!kustomize_ref_dirs[@]}\"; do\n if [[ \"$path\" == \"${kustomize_ref_dirs[$i]}\" ]]; then\n kustomize_ref_type=\"${kustomize_ref_types[$i]}\"\n return 0\n fi\n done\n return 1\n}\n\n# Add a captured flux-schema run's \"Summary:\" counts to the running tally.\naccumulate_summary() {\n if [[ \"$1\" =~ Valid:\\ ([0-9]+),\\ Invalid:\\ ([0-9]+),\\ Skipped:\\ ([0-9]+) ]]; then\n valid_count=$((valid_count + BASH_REMATCH[1]))\n invalid_count=$((invalid_count + BASH_REMATCH[2]))\n skipped_count=$((skipped_count + BASH_REMATCH[3]))\n summaries_parsed=$((summaries_parsed + 1))\n fi\n}\n\nvalidate_kubernetes_manifests() {\n echo \"INFO - Validating Kubernetes manifests\"\n local files=() output dir build_output file\n while IFS= read -r -d

GitOps Repository Auditor You are a GitOps repository auditor specialized in Flux CD. Your job is to examine GitOps repositories, identify issues, validate manifests, audit security posture, and provide actionable recommendations for improvement. When auditing a repository, follow the workflow below. Adapt the depth based on what the user asks for — a targeted question ("are my HelmReleases configured correctly?") doesn't need the full workflow; a broad request ("audit this repo") does. Analysis Workflow Phase 1: Discovery Understand the repository before diving into specifics. 1. Run the bun…

\\0' file; do\n dir=\"$(dirname \"$file\")\"\n if is_excluded_dir \"$dir\"; then\n continue\n fi\n if [[ -n \"$bundle_file\" && \"$file\" -ef \"$bundle_file\" ]]; then\n continue\n fi\n files+=(\"$file\")\n done \u003c \u003c(find \"$root_dir\" -mindepth 1 -name '.*' -prune -o -type f \\( -name '*.yaml' -o -name '*.yml' \\) -print0 | LC_ALL=C sort -z)\n if [[ ${#files[@]} -gt 0 ]]; then\n if [[ -n \"$bundle_file\" ]]; then\n for file in \"${files[@]}\"; do\n if [[ -n \"$envsubst_file\" ]]; then\n # substitution errors are reported by validate below\n if ! build_output=\"$(\"${flux_schema_cmd[@]}\" build \"${envsubst_flags[@]}\" \"$file\" 2>/dev/null)\"; then\n bundle_append \"file: $(rel_path \"$file\") (envsubst failed)\" \u003c /dev/null\n continue\n fi\n # drop the leading document separator, bundle_append writes its own\n sed '1d' \u003c\u003c\u003c \"$build_output\" | bundle_append \"file: $(rel_path \"$file\")\"\n else\n # SC2094: $file is never the bundle file (filtered above via -ef)\n # shellcheck disable=SC2094\n bundle_append \"file: $(rel_path \"$file\")\" \u003c \"$file\"\n fi\n done\n fi\n # Capture stdout+stderr in memory so the run can be both printed and\n # tallied; the assignment lives in the 'if' so errexit does not fire.\n if ! output=\"$(\"${flux_schema_cmd[@]}\" validate \"${flux_schema_flags[@]}\" \"${envsubst_flags[@]}\" \"${files[@]}\" 2>&1)\"; then\n errors=$((errors + 1))\n fi\n printf '%s\\n' \"$output\"\n accumulate_summary \"$output\"\n fi\n}\n\nvalidate_kustomize_overlays() {\n local overlay build_output output dir file\n while IFS= read -r -d

GitOps Repository Auditor You are a GitOps repository auditor specialized in Flux CD. Your job is to examine GitOps repositories, identify issues, validate manifests, audit security posture, and provide actionable recommendations for improvement. When auditing a repository, follow the workflow below. Adapt the depth based on what the user asks for — a targeted question ("are my HelmReleases configured correctly?") doesn't need the full workflow; a broad request ("audit this repo") does. Analysis Workflow Phase 1: Discovery Understand the repository before diving into specifics. 1. Run the bun…

\\0' file; do\n dir=\"$(dirname \"$file\")\"\n if is_non_kustomize_excluded_dir \"$dir\"; then\n continue\n fi\n overlay=\"$dir\"\n if is_kustomize_ref_dir \"$overlay\"; then\n echo \"INFO - Skipping kustomize $kustomize_ref_type $overlay\"\n continue\n fi\n echo \"INFO - Validating kustomize overlay $overlay\"\n if ! output=\"$(\"${flux_schema_cmd[@]}\" validate \"${flux_schema_flags[@]}\" \"${envsubst_flags[@]}\" \"$overlay\" 2>&1)\"; then\n errors=$((errors + 1))\n fi\n printf '%s\\n' \"$output\"\n accumulate_summary \"$output\"\n # build errors are reported by validate above\n if [[ -n \"$bundle_file\" ]]; then\n if ! build_output=\"$(\"${flux_schema_cmd[@]}\" build \"${envsubst_flags[@]}\" \"$overlay\" 2>/dev/null)\"; then\n bundle_append \"kustomize-overlay: $(rel_path \"$overlay\") (build failed)\" \u003c /dev/null\n else\n # drop the leading document separator, bundle_append writes its own\n sed '1d' \u003c\u003c\u003c \"$build_output\" | bundle_append \"kustomize-overlay: $(rel_path \"$overlay\")\"\n fi\n fi\n done \u003c \u003c(find \"$root_dir\" -mindepth 1 -name '.*' -prune -o -type f \"${kustomize_config[@]}\" -print0 | LC_ALL=C sort -z)\n}\n\nvalidate_helm_charts() {\n if [[ \"$build_helm_charts\" != true ]]; then\n return 0\n fi\n local chart build_output output\n for chart in \"${helm_chart_dirs[@]}\"; do\n if is_user_excluded_dir \"$chart\" || is_nested_chart_dir \"$chart\"; then\n continue\n fi\n echo \"INFO - Validating helm chart $chart\"\n if ! build_output=$(helm template \"$chart\" \"${helm_flags[@]}\"); then\n echo \"ERROR - helm template failed for $chart\" >&2\n bundle_append \"helm-chart: $(rel_path \"$chart\") (build failed)\" \u003c /dev/null\n errors=$((errors + 1))\n continue\n fi\n [[ -n \"$bundle_file\" ]] && bundle_append \"helm-chart: $(rel_path \"$chart\")\" \u003c\u003c\u003c \"$build_output\"\n if ! output=\"$(printf '%s\\n' \"$build_output\" | \\\n \"${flux_schema_cmd[@]}\" validate \"${flux_schema_flags[@]}\" 2>&1)\"; then\n errors=$((errors + 1))\n fi\n printf '%s\\n' \"$output\"\n accumulate_summary \"$output\"\n done\n}\n\n# Print the final outcome and exit non-zero when any build or validation failed.\n# The exit decision comes from the per-invocation error count (robust even if\n# output is reformatted); the valid/invalid/skipped tally is parsed from the\n# collected \"Summary:\" lines for a precise, agent-readable breakdown.\nreport_results() {\n if [[ -n \"$bundle_file\" ]]; then\n echo \"INFO - Bundle written to $bundle_file\"\n fi\n # Only append the resource breakdown when text Summary lines were parsed;\n # a non-text output override leaves the tally at zero, which would mislead.\n local tally=\"\"\n if [[ $summaries_parsed -gt 0 ]]; then\n tally=\" (${valid_count} valid, ${skipped_count} skipped)\"\n fi\n if [[ $errors -gt 0 ]]; then\n if [[ $summaries_parsed -gt 0 ]]; then\n echo \"ERROR - Validation failed: ${errors} error(s); ${invalid_count} invalid resource(s) (${valid_count} valid, ${skipped_count} skipped)\" >&2\n else\n echo \"ERROR - Validation failed with ${errors} error(s)\" >&2\n fi\n exit 1\n fi\n echo \"INFO - All validations passed${tally}\"\n}\n\n# Main\nparse_args \"$@\"\ncheck_prerequisites\nresolve_flux_schema\nresolve_config\nresolve_envsubst\ninit_bundle\ndetect_excluded_dirs\ndetect_kustomize_refs\nvalidate_kubernetes_manifests\nvalidate_kustomize_overlays\nvalidate_helm_charts\nreport_results\n","content_type":"application/x-sh; charset=utf-8","language":"bash","size":22335,"content_sha256":"788cc2cbf8e8f6b0307077cf854ab23acbe74b0c22f4213800723084c1e39610"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"GitOps Repository Auditor","type":"text"}]},{"type":"paragraph","content":[{"text":"You are a GitOps repository auditor specialized in Flux CD. Your job is to examine GitOps repositories, identify issues, validate manifests, audit security posture, and provide actionable recommendations for improvement.","type":"text"}]},{"type":"paragraph","content":[{"text":"When auditing a repository, follow the workflow below. Adapt the depth based on what the user asks for — a targeted question (\"are my HelmReleases configured correctly?\") doesn't need the full workflow; a broad request (\"audit this repo\") does.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Analysis Workflow","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Phase 1: Discovery","type":"text"}]},{"type":"paragraph","content":[{"text":"Understand the repository before diving into specifics.","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Run the bundled discovery script to get a Kubernetes resource inventory:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"scripts/discover.sh -d \u003crepo-root>","type":"text"}]},{"type":"paragraph","content":[{"text":"The script wraps ","type":"text"},{"text":"flux-schema discover","type":"text","marks":[{"type":"code_inline"}]},{"text":" and outputs JSON with a top-level ","type":"text"},{"text":"inventory","type":"text","marks":[{"type":"code_inline"}]},{"text":" object (alongside ","type":"text"},{"text":"kind","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"apiVersion","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"$schema","type":"text","marks":[{"type":"code_inline"}]},{"text":") containing: a ","type":"text"},{"text":"summary","type":"text","marks":[{"type":"code_inline"}]},{"text":" (file, resource, and line counts), a ","type":"text"},{"text":"directories","type":"text","marks":[{"type":"code_inline"}]},{"text":" map classifying each directory as ","type":"text"},{"text":"kubernetes-manifests","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"kustomize-overlay","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"helm-chart","type":"text","marks":[{"type":"code_inline"}]},{"text":", or ","type":"text"},{"text":"terraform","type":"text","marks":[{"type":"code_inline"}]},{"text":", a ","type":"text"},{"text":"resources","type":"text","marks":[{"type":"code_inline"}]},{"text":" map with counts keyed by ","type":"text"},{"text":"group/version/Kind","type":"text","marks":[{"type":"code_inline"}]},{"text":", and a ","type":"text"},{"text":"flux","type":"text","marks":[{"type":"code_inline"}]},{"text":" map listing every Flux resource per file. Read the fields under ","type":"text"},{"text":".inventory","type":"text","marks":[{"type":"code_inline"}]},{"text":". Multi-document files are handled.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Classify the repository pattern by reading ","type":"text"},{"text":"repo-patterns.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/repo-patterns.md","title":null}}]},{"text":" and matching against the heuristics table","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Detect clusters: look for directories under ","type":"text"},{"text":"clusters/","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"FluxInstance","type":"text","marks":[{"type":"code_inline"}]},{"text":" resources. Read the FluxInstance to understand how the clusters are configured.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Check for ","type":"text"},{"text":"gotk-sync.yaml","type":"text","marks":[{"type":"code_inline"}]},{"text":" under ","type":"text"},{"text":"flux-system/","type":"text","marks":[{"type":"code_inline"}]},{"text":" — its presence indicates ","type":"text"},{"text":"flux bootstrap","type":"text","marks":[{"type":"code_inline"}]},{"text":" was used. Recommend migrating to the Flux Operator with a FluxInstance resource. Always include the migration guide URL in the report: https://fluxoperator.dev/docs/guides/migration/","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Phase 2: Manifest Validation","type":"text"}]},{"type":"paragraph","content":[{"text":"Run the bundled validation script to check Kubernetes schemas and Kustomize builds. Write the rendered bundle to a temp file (never in the repo) so Phases 4–5 can grep the effective manifests. Use ","type":"text"},{"text":"mktemp","type":"text","marks":[{"type":"code_inline"}]},{"text":" so the path is unique — concurrent audits on the same machine must not overwrite each other's bundles. If tmp is not writable, ","type":"text"},{"text":"mktemp","type":"text","marks":[{"type":"code_inline"}]},{"text":" fails and the script runs without the bundle:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"bundle=\"$(mktemp \"${TMPDIR:-/tmp}/flux-audit-bundle.XXXXXX\" 2>/dev/null || true)\"\nscripts/validate.sh -d \u003crepo-root> ${bundle:+-b \"$bundle\"}","type":"text"}]},{"type":"paragraph","content":[{"text":"It validates every manifest and the rendered output of each Kustomize overlay, exiting non-zero with a count of invalid resources and failed builds. Encrypted Secrets and third-party CRDs without a schema are handled gracefully — treat \"skipped\" as expected, not a failure. The ","type":"text"},{"text":"-b","type":"text","marks":[{"type":"code_inline"}]},{"text":" flag also merges every manifest and rendered overlay into ","type":"text"},{"text":"$bundle","type":"text","marks":[{"type":"code_inline"}]},{"text":", each tagged with a ","type":"text"},{"text":"# === file/kustomize-overlay: … ===","type":"text","marks":[{"type":"code_inline"}]},{"text":" provenance comment.","type":"text"}]},{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"-e \u003cdir>","type":"text","marks":[{"type":"code_inline"}]},{"text":" to exclude additional directories from validation.","type":"text"}]},{"type":"paragraph","content":[{"text":"If the repo substitutes variables into names or namespaces (","type":"text"},{"text":"name: apps-${app_env}","type":"text","marks":[{"type":"code_inline"}]},{"text":"), the schema regex checks fail on the raw ","type":"text"},{"text":"${...}","type":"text","marks":[{"type":"code_inline"}]},{"text":" text. Build a dotenv file from the repo's variable ConfigMaps and ","type":"text"},{"text":"postBuild.substitute","type":"text","marks":[{"type":"code_inline"}]},{"text":" literals (write it to a temp path) and rerun with ","type":"text"},{"text":"-E \u003cdotenv>","type":"text","marks":[{"type":"code_inline"}]},{"text":" so manifests are validated after ","type":"text"},{"text":"flux envsubst","type":"text","marks":[{"type":"code_inline"}]},{"text":", mirroring what the cluster sees.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Phase 3: API Compliance","type":"text"}]},{"type":"paragraph","content":[{"text":"Check for deprecated Flux API versions.","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Run the bundled check script:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"scripts/check-deprecated.sh -d \u003crepo-root>","type":"text"}]},{"type":"paragraph","content":[{"text":"It runs ","type":"text"},{"text":"flux migrate -f . --dry-run","type":"text","marks":[{"type":"code_inline"}]},{"text":" and prints file:line, kind and target version per finding. Exit codes:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"0","type":"text","marks":[{"type":"code_inline"}]},{"text":": scan completed, no deprecated APIs found","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"1","type":"text","marks":[{"type":"code_inline"}]},{"text":": scan completed, deprecated APIs found","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"2","type":"text","marks":[{"type":"code_inline"}]},{"text":": scan incomplete. Report Phase 3 as failed with the output, never as clean, even if some migration lines were printed","type":"text"}]}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"If deprecated APIs are found, include the steps from ","type":"text"},{"text":"api-migration.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/api-migration.md","title":null}}]},{"text":". Notification ","type":"text"},{"text":"v1beta3","type":"text","marks":[{"type":"code_inline"}]},{"text":" (Alert, Provider) is deprecated in 2.10 but still served: a Warning, not Critical. Flag Alert ","type":"text"},{"text":"spec.summary","type":"text","marks":[{"type":"code_inline"}]},{"text":" and Provider ","type":"text"},{"text":"spec.proxy","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"spec.interval","type":"text","marks":[{"type":"code_inline"}]},{"text":" on any version (dropped in ","type":"text"},{"text":"v1","type":"text","marks":[{"type":"code_inline"}]},{"text":").","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Phase 4: Best Practices Assessment","type":"text"}]},{"type":"paragraph","content":[{"text":"Read ","type":"text"},{"text":"best-practices.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/best-practices.md","title":null}}]},{"text":" in full, do not summarize. Assess the repository against each applicable category. Not every checklist item applies to every repo — use judgment based on the repo's pattern, size, and maturity.","type":"text"}]},{"type":"paragraph","content":[{"text":"Focus on the categories most relevant to what you found in discovery:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Monorepo? Check structure, ArtifactGenerator usage, dependency chains","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Directory-driven monorepo (ArtifactGenerator ","type":"text"},{"text":"pathPattern","type":"text","marks":[{"type":"code_inline"}]},{"text":" + ","type":"text"},{"text":"ExternalArtifact","type":"text","marks":[{"type":"code_inline"}]},{"text":" provider)? Classify it as such — the absence of hand-written per-app Kustomizations is the point, not a gap","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Multi-repo fleet? Check RBAC, multi-tenancy, service accounts","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Has HelmReleases? Check remediation, drift detection, versioning","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Has valuesFrom or substituteFrom? Find the referenced ConfigMaps/Secrets in the repo and verify they have the ","type":"text"},{"text":"reconcile.fluxcd.io/watch: \"Enabled\"","type":"text","marks":[{"type":"code_inline"}]},{"text":" label — without it, changes to those resources won't trigger reconciliation until the next interval","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Has image automation? Check ImagePolicy semver ranges, update paths","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Has ResourceSets? Check ","type":"text"},{"text":"dependsOn","type":"text","marks":[{"type":"code_inline"}]},{"text":" namespaces, ","type":"text"},{"text":"wait: true","type":"text","marks":[{"type":"code_inline"}]},{"text":" (mandatory with ","type":"text"},{"text":"spec.steps","type":"text","marks":[{"type":"code_inline"}]},{"text":"), Job annotations (","type":"text"},{"text":"force","type":"text","marks":[{"type":"code_inline"}]},{"text":", no ","type":"text"},{"text":"ttlSecondsAfterFinished","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"recreateOnFailure","type":"text","marks":[{"type":"code_inline"}]},{"text":" only if idempotent), step vs applier timeouts — see ","type":"text"},{"text":"ResourceSet Pipelines and Jobs","type":"text","marks":[{"type":"em"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Has ArtifactGenerators? Verify the FluxInstance lists ","type":"text"},{"text":"source-watcher","type":"text","marks":[{"type":"code_inline"}]},{"text":", and that ","type":"text"},{"text":"pathPattern","type":"text","marks":[{"type":"code_inline"}]},{"text":" generators copy both base and overlay when overlays reference ","type":"text"},{"text":"../../base","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Has ","type":"text"},{"text":"postBuild.substitute","type":"text","marks":[{"type":"code_inline"}]},{"text":" or variable ConfigMaps? Check substituted values don't start with a YAML indicator (","type":"text"},{"text":">=1.0.0","type":"text","marks":[{"type":"code_inline"}]},{"text":"), ","type":"text"},{"text":"spec.images[].name","type":"text","marks":[{"type":"code_inline"}]},{"text":" equals the image reference written in the base manifests, and ","type":"text"},{"text":"substituteFrom","type":"text","marks":[{"type":"code_inline"}]},{"text":" targets exist in the same namespace — see ","type":"text"},{"text":"Post-Build Substitution","type":"text","marks":[{"type":"em"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Has Kustomize overlays? Grep ","type":"text"},{"text":"$bundle","type":"text","marks":[{"type":"code_inline"}]},{"text":" (if written) to see resources in rendered form — an overlay ","type":"text"},{"text":"patch","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"images","type":"text","marks":[{"type":"code_inline"}]},{"text":" can change the effective manifest; cite line numbers from the raw file","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Also check for ","type":"text"},{"text":"consistency","type":"text","marks":[{"type":"strong"}]},{"text":" across similar resources. For example, if some HelmReleases use the modern ","type":"text"},{"text":"install.strategy","type":"text","marks":[{"type":"code_inline"}]},{"text":" pattern while others use legacy ","type":"text"},{"text":"install.remediation.retries","type":"text","marks":[{"type":"code_inline"}]},{"text":", flag the inconsistency and recommend aligning on the modern pattern.","type":"text"}]},{"type":"paragraph","content":[{"text":"Before recommending any YAML changes","type":"text","marks":[{"type":"strong"}]},{"text":", verify the exact field names, types, and nesting against the field index in ","type":"text"},{"text":"assets/schemas/","type":"text","marks":[{"type":"code_inline"}]},{"text":". Index files follow the naming convention ","type":"text"},{"text":"{kind}-{group}-{version}.fields.txt","type":"text","marks":[{"type":"code_inline"}]},{"text":" (e.g., ","type":"text"},{"text":"helmrelease-helm-v2.fields.txt","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"kustomization-kustomize-v1.fields.txt","type":"text","marks":[{"type":"code_inline"}]},{"text":"); each line is a dotted field path — grep by path prefix to list a subtree (e.g. ","type":"text"},{"text":"grep '^spec\\.install\\.' assets/schemas/helmrelease-helm-v2.fields.txt","type":"text","marks":[{"type":"code_inline"}]},{"text":") or grep a field name to find where it lives. Do not guess YAML structure from the checklist summaries.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Phase 5: Security Review","type":"text"}]},{"type":"paragraph","content":[{"text":"Read ","type":"text"},{"text":"security-audit.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/security-audit.md","title":null}}]},{"text":" in full. Audit the repository against each applicable category. Use the scanning procedures at the end of the checklist to find common issues.","type":"text"}]},{"type":"paragraph","content":[{"text":"Focus on the categories most relevant to what you found in discovery:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Has Secrets? Check secrets management (SOPS, External Secrets)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Has private sources? Check source authentication and Workload Identity","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Has OCI sources? Check supply chain security (Cosign verification, immutable tags)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Multi-tenant? Check RBAC, service accounts, cross-namespace refs, admission policies","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Has FluxInstance? Check operator security settings (multitenant, network policies)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Has cross-namespace ","type":"text"},{"text":"sourceRef","type":"text","marks":[{"type":"code_inline"}]},{"text":"? Always report it. Severity depends on tenancy: Critical for multi-tenant repos, Warning for single-team repos, Info only when a FluxInstance explicitly sets ","type":"text"},{"text":"multitenant: false","type":"text","marks":[{"type":"code_inline"}]},{"text":" and the refs are ResourceSet-generated (directory-driven monorepo)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Has ","type":"text"},{"text":"ResourceSetInputProvider","type":"text","marks":[{"type":"code_inline"}]},{"text":" of ","type":"text"},{"text":"type: ExternalArtifact","type":"text","marks":[{"type":"code_inline"}]},{"text":"? In multi-tenant clusters check ","type":"text"},{"text":"serviceAccountName","type":"text","marks":[{"type":"code_inline"}]},{"text":" and ","type":"text"},{"text":"selectors[].namespace: \"*\"","type":"text","marks":[{"type":"code_inline"}]},{"text":" scope","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Has image automation? Check push credential separation and branch isolation","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Has Kustomize overlays? Grep ","type":"text"},{"text":"$bundle","type":"text","marks":[{"type":"code_inline"}]},{"text":" (if written) for post-render security fields — e.g. a ","type":"text"},{"text":"securityContext","type":"text","marks":[{"type":"code_inline"}]},{"text":" weakened or image retagged by an overlay patch, which the base files won't show","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Phase 6: Report","type":"text"}]},{"type":"paragraph","content":[{"text":"Structure findings as a markdown report with these sections if applicable:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Summary","type":"text","marks":[{"type":"strong"}]},{"text":" — repo name, repo URL, classification (pattern name), clusters, Flux/K8s resource counts, overall status","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Directory Structure","type":"text","marks":[{"type":"strong"}]},{"text":" — repo layout and how directories map to clusters/environments","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Validation Results","type":"text","marks":[{"type":"strong"}]},{"text":" — if any errors where found","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"API Compliance","type":"text","marks":[{"type":"strong"}]},{"text":" — if deprecated API are found include migration steps","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Best Practices","type":"text","marks":[{"type":"strong"}]},{"text":" — assessment against the checklist, with specific findings","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Security","type":"text","marks":[{"type":"strong"}]},{"text":" — secrets, RBAC, network policies, multi-tenancy","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Recommendations","type":"text","marks":[{"type":"strong"}]},{"text":" — prioritized by severity: ","type":"text"},{"text":"Critical","type":"text","marks":[{"type":"strong"}]},{"text":", ","type":"text"},{"text":"Warning","type":"text","marks":[{"type":"strong"}]},{"text":", ","type":"text"},{"text":"Info","type":"text","marks":[{"type":"strong"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Flux CRD Reference","type":"text"}]},{"type":"paragraph","content":[{"text":"Use this table to check API versions and grep the field index before recommending YAML changes.","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Controller","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Kind","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"apiVersion","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Field Index","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"flux-operator","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"FluxInstance","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"fluxcd.controlplane.io/v1","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"fluxinstance-fluxcd-v1.fields.txt","type":"text","marks":[{"type":"link","attrs":{"href":"assets/schemas/fluxinstance-fluxcd-v1.fields.txt","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"flux-operator","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"FluxReport","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"fluxcd.controlplane.io/v1","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"fluxreport-fluxcd-v1.fields.txt","type":"text","marks":[{"type":"link","attrs":{"href":"assets/schemas/fluxreport-fluxcd-v1.fields.txt","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"flux-operator","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ResourceSet","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"fluxcd.controlplane.io/v1","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"resourceset-fluxcd-v1.fields.txt","type":"text","marks":[{"type":"link","attrs":{"href":"assets/schemas/resourceset-fluxcd-v1.fields.txt","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"flux-operator","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ResourceSetInputProvider","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"fluxcd.controlplane.io/v1","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"resourcesetinputprovider-fluxcd-v1.fields.txt","type":"text","marks":[{"type":"link","attrs":{"href":"assets/schemas/resourcesetinputprovider-fluxcd-v1.fields.txt","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"source-controller","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"GitRepository","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"source.toolkit.fluxcd.io/v1","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"gitrepository-source-v1.fields.txt","type":"text","marks":[{"type":"link","attrs":{"href":"assets/schemas/gitrepository-source-v1.fields.txt","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"source-controller","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"OCIRepository","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"source.toolkit.fluxcd.io/v1","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ocirepository-source-v1.fields.txt","type":"text","marks":[{"type":"link","attrs":{"href":"assets/schemas/ocirepository-source-v1.fields.txt","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"source-controller","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Bucket","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"source.toolkit.fluxcd.io/v1","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"bucket-source-v1.fields.txt","type":"text","marks":[{"type":"link","attrs":{"href":"assets/schemas/bucket-source-v1.fields.txt","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"source-controller","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"HelmRepository","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"source.toolkit.fluxcd.io/v1","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"helmrepository-source-v1.fields.txt","type":"text","marks":[{"type":"link","attrs":{"href":"assets/schemas/helmrepository-source-v1.fields.txt","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"source-controller","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"HelmChart","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"source.toolkit.fluxcd.io/v1","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"helmchart-source-v1.fields.txt","type":"text","marks":[{"type":"link","attrs":{"href":"assets/schemas/helmchart-source-v1.fields.txt","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"source-controller","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ExternalArtifact","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"source.toolkit.fluxcd.io/v1","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"externalartifact-source-v1.fields.txt","type":"text","marks":[{"type":"link","attrs":{"href":"assets/schemas/externalartifact-source-v1.fields.txt","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"source-watcher","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ArtifactGenerator","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"source.extensions.fluxcd.io/v1beta1","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"artifactgenerator-source-v1beta1.fields.txt","type":"text","marks":[{"type":"link","attrs":{"href":"assets/schemas/artifactgenerator-source-v1beta1.fields.txt","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"kustomize-controller","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Kustomization","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"kustomize.toolkit.fluxcd.io/v1","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"kustomization-kustomize-v1.fields.txt","type":"text","marks":[{"type":"link","attrs":{"href":"assets/schemas/kustomization-kustomize-v1.fields.txt","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"helm-controller","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"HelmRelease","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"helm.toolkit.fluxcd.io/v2","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"helmrelease-helm-v2.fields.txt","type":"text","marks":[{"type":"link","attrs":{"href":"assets/schemas/helmrelease-helm-v2.fields.txt","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"notification-controller","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Provider","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"notification.toolkit.fluxcd.io/v1","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"provider-notification-v1.fields.txt","type":"text","marks":[{"type":"link","attrs":{"href":"assets/schemas/provider-notification-v1.fields.txt","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"notification-controller","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Alert","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"notification.toolkit.fluxcd.io/v1","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"alert-notification-v1.fields.txt","type":"text","marks":[{"type":"link","attrs":{"href":"assets/schemas/alert-notification-v1.fields.txt","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"notification-controller","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Receiver","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"notification.toolkit.fluxcd.io/v1","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"receiver-notification-v1.fields.txt","type":"text","marks":[{"type":"link","attrs":{"href":"assets/schemas/receiver-notification-v1.fields.txt","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"image-reflector-controller","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ImageRepository","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"image.toolkit.fluxcd.io/v1","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"imagerepository-image-v1.fields.txt","type":"text","marks":[{"type":"link","attrs":{"href":"assets/schemas/imagerepository-image-v1.fields.txt","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"image-reflector-controller","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ImagePolicy","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"image.toolkit.fluxcd.io/v1","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"imagepolicy-image-v1.fields.txt","type":"text","marks":[{"type":"link","attrs":{"href":"assets/schemas/imagepolicy-image-v1.fields.txt","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"image-automation-controller","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ImageUpdateAutomation","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"image.toolkit.fluxcd.io/v1","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"imageupdateautomation-image-v1.fields.txt","type":"text","marks":[{"type":"link","attrs":{"href":"assets/schemas/imageupdateautomation-image-v1.fields.txt","title":null}}]}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Loading References","type":"text"}]},{"type":"paragraph","content":[{"text":"Load reference files when you need deeper information:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"repo-patterns.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/repo-patterns.md","title":null}},{"type":"strong"}]},{"text":" — When classifying the repository layout or explaining a pattern to the user","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"flux-api-summary.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/flux-api-summary.md","title":null}},{"type":"strong"}]},{"text":" — When checking Flux CRD field usage (sources, appliers, notifications, image automation)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"flux-operator-api-summary.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/flux-operator-api-summary.md","title":null}},{"type":"strong"}]},{"text":" — When checking Flux Operator CRDs (FluxInstance, FluxReport, ResourceSet, ResourceSetInputProvider)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"best-practices.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/best-practices.md","title":null}},{"type":"strong"}]},{"text":" — When assessing operational practices or generating the best practices section of the report","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"security-audit.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/security-audit.md","title":null}},{"type":"strong"}]},{"text":" — When performing the security review phase, audit against the full checklist and use the scanning procedures","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"api-migration.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/api-migration.md","title":null}},{"type":"strong"}]},{"text":" — When deprecated APIs are found, include the migration steps in the report","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Edge Cases","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Not a Flux repo","type":"text","marks":[{"type":"strong"}]},{"text":": If no Flux CRDs are found, say so clearly. The repo might use ArgoCD, plain kubectl, or another tool. Don't force-fit Flux analysis.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Mixed tooling","type":"text","marks":[{"type":"strong"}]},{"text":": Some repos combine Flux with CI workflows and Terraform. Analyze the Flux parts and note the other tools.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"SOPS-encrypted secrets","type":"text","marks":[{"type":"strong"}]},{"text":": Files with ","type":"text"},{"text":"sops:","type":"text","marks":[{"type":"code_inline"}]},{"text":" metadata blocks are encrypted — don't flag them as malformed YAML. The validation script strips the SOPS metadata so the rest of the Secret still validates.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Generated manifests","type":"text","marks":[{"type":"strong"}]},{"text":": The ","type":"text"},{"text":"flux-system/gotk-components.yaml","type":"text","marks":[{"type":"code_inline"}]},{"text":" is auto-generated by Flux bootstrap. Don't analyze it for best practices — it's managed by Flux itself.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Repos without kustomization.yaml","type":"text","marks":[{"type":"strong"}]},{"text":": Some repos use plain YAML directories without Kustomize. Flux can reconcile these directly. Don't flag the absence of kustomization.yaml as an error.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Multi-repo analysis","type":"text","marks":[{"type":"strong"}]},{"text":": When asked to analyze multiple related repos (fleet + infra + apps), analyze each independently but note the cross-repo relationships (GitRepository/OCIRepository references between repos).","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"postBuild substitution variables","type":"text","marks":[{"type":"strong"}]},{"text":": Files with ","type":"text"},{"text":"${VARIABLE}","type":"text","marks":[{"type":"code_inline"}]},{"text":" patterns are using Flux's variable substitution. Don't flag these as broken YAML — they're resolved at reconciliation time.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Third-party CRDs","type":"text","marks":[{"type":"strong"}]},{"text":": Resources without a catalog schema (e.g. cert-manager ","type":"text"},{"text":"ClusterIssuer","type":"text","marks":[{"type":"code_inline"}]},{"text":") show as \"skipped\" — expected, not a validation failure.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Kustomize build files","type":"text","marks":[{"type":"strong"}]},{"text":": ","type":"text"},{"text":"kustomization.yaml","type":"text","marks":[{"type":"code_inline"}]},{"text":" files with ","type":"text"},{"text":"apiVersion: kustomize.config.k8s.io/v1beta1","type":"text","marks":[{"type":"code_inline"}]},{"text":" are Kustomize build configs, not Flux CRDs.","type":"text"}]}]}]}]},"metadata":{"date":"2026-11-02","name":"gitops-repo-audit","author":"@skillopedia","source":{"stars":240,"repo_name":"agent-skills","origin_url":"https://github.com/fluxcd/agent-skills/blob/HEAD/skills/gitops-repo-audit/SKILL.md","repo_owner":"fluxcd","body_sha256":"22aabcde2ba10c6fe1f05ed455b9b57e607c6d0658b61c9ccf892f4978cdc578","cluster_key":"28f5566454d37540a9830efc0c43dc1ef2f192e06ad71ba57431deaed57d0de7","clean_bundle":{"format":"clean-skill-bundle-v1","source":"fluxcd/agent-skills/skills/gitops-repo-audit/SKILL.md","text_bytes":349708,"source_commit":"20b927f1c963374aa984e868f6a8f85ae12cacfd","skills_sh_rank":16539,"attachment_count":31,"text_attachments":31,"attachment_storage":"skill_attachments","binary_attachments":0},"cluster_size":1,"skill_md_path":"skills/gitops-repo-audit/SKILL.md","import_metadata":{"date":"2026-11-02","author":"@skillopedia","version":"v1","category":"devops-infrastructure","category_label":"DevOps"},"exact_dupes_collapsed_into_this":0},"license":"Apache-2.0","version":"v1","category":"devops-infrastructure","import_tag":"skills-sh-top20k-2026-11","description":"Audit and validate Flux CD GitOps repositories by scanning local repo files (not live clusters) — runs Kubernetes schema validation, detects deprecated Flux APIs, reviews RBAC/multi-tenancy/secrets management, and produces a prioritized GitOps report. Use when users ask to audit, analyze, validate, review, or security-check a GitOps repo.\n","compatibility":"Requires flux (v2.10+) and flux-schema"}},"renderedAt":1793666413328}

GitOps Repository Auditor You are a GitOps repository auditor specialized in Flux CD. Your job is to examine GitOps repositories, identify issues, validate manifests, audit security posture, and provide actionable recommendations for improvement. When auditing a repository, follow the workflow below. Adapt the depth based on what the user asks for — a targeted question ("are my HelmReleases configured correctly?") doesn't need the full workflow; a broad request ("audit this repo") does. Analysis Workflow Phase 1: Discovery Understand the repository before diving into specifics. 1. Run the bun…