Skip to content

Conversation

@verbotenj
Copy link
Contributor

@verbotenj verbotenj commented Nov 4, 2025

closes #13

  • use a secret for credentials

Summary by CodeRabbit

  • New Features

    • Added reusable CI workflows to run Helmfile operations with selectable cluster and argument inputs, plus PR, manual-run, and test triggers.
  • Security Improvements

    • Replaced embedded Grafana credentials with environment-sourced secrets and added secret injection for runtime.
    • Updated encrypted secret metadata following a recent secret rotation.
  • Chores

    • Normalized CI workflow trigger formatting.

@verbotenj verbotenj requested review from a team as code owners November 4, 2025 15:45
@coderabbitai
Copy link

coderabbitai bot commented Nov 4, 2025

📝 Walkthrough

Walkthrough

Adds a reusable GitHub Actions workflow at .github/workflows/common-helmfile.yml that accepts inputs cluster and arguments and runs a job performing checkout, kubectl install, sops installer, conditional AWS credential/CLI/EKS setup (when cluster == 'aws-vpn'), and a Helmfile execution step (explicit Helmfile/Helm versions, plugins, workdir helmfile-app, and passed args). Adds three workflows that reuse it: .github/workflows/pr-helmfile.yml (PR trigger for changes under helmfile-app/**), .github/workflows/run-helmfile.yml (workflow_dispatch with inputs), and .github/workflows/test-helmfile.yml (workflow_dispatch with required cluster). Updates helmfile-app/grafana-alloy/values.yaml.gotmpl to source Grafana credentials from env vars and inject a grafana-cloud Secret via extraObjects. Updates SOPS-encrypted fields and metadata in helmfile-app/vars/secrets.yaml. Minor formatting changes in .github/workflows/test-terraform.yml triggers.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Inspect .github/workflows/common-helmfile.yml for correctness of conditional AWS/EKS steps, secrets handling, and the helmfile-action configuration (versions, plugins, workdir, passed args, and disabled auto-init).
  • Verify reuse and input propagation in .github/workflows/pr-helmfile.yml, .github/workflows/run-helmfile.yml, and .github/workflows/test-helmfile.yml.
  • Review helmfile-app/grafana-alloy/values.yaml.gotmpl to confirm env var names, extraEnv wiring, and the extraObjects Secret does not expose plaintext in templates.
  • Check helmfile-app/vars/secrets.yaml SOPS metadata and encrypted values for intended changes (no plaintext leakage).

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR includes an out-of-scope change: reformatting of .github/workflows/test-terraform.yml with no functional changes, unrelated to the GHA workflows objective. Remove the test-terraform.yml formatting changes as they are unrelated to the primary objective of adding Helmfile deployment workflows.
Title check ❓ Inconclusive The title 'ci: add GHA' is vague and does not clearly convey what GitHub Actions workflows are being added or their purpose. Use a more descriptive title such as 'ci: add Helmfile deployment workflows' to clarify which workflows are being introduced.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed The PR successfully implements GitHub Actions workflows for CI/CD and properly uses Kubernetes Secrets for storing sensitive credentials (Grafana credentials in Secret resources).
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/add-gha

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

jobs:
run-helmfile:
name: run-helmfile
runs-on: ["self-hosted"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why self-hosted?

@verbotenj verbotenj force-pushed the feat/add-gha branch 2 times, most recently from e81f18b to fd62585 Compare November 4, 2025 15:55
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
helmfile-app/grafana-alloy/values.yaml.gotmpl (1)

167-175: Consider moving the Grafana username to encrypted secrets.

While the password is properly templated from encrypted secrets ({{ .Values.grafana.password }}), the username is hardcoded as "1834751". For consistency and better secret management, consider moving the username to helmfile-app/vars/secrets.yaml and templating it similarly to the password.

Apply this diff to improve secret management:

   stringData:
-    GRAFANA_USERNAME: "1834751"
+    GRAFANA_USERNAME: "{{ .Values.grafana.username }}"
     GRAFANA_PASSWORD: "{{ .Values.grafana.password }}"

Then add the username to helmfile-app/vars/secrets.yaml:

grafana:
    username: ENC[...]
    password: ENC[...]
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3234fd0 and e2e0984.

📒 Files selected for processing (7)
  • .github/workflows/common-helmfile.yml (1 hunks)
  • .github/workflows/pr-helmfile.yml (1 hunks)
  • .github/workflows/run-helmfile.yml (1 hunks)
  • .github/workflows/test-helmfile.yml (1 hunks)
  • .github/workflows/test-terraform.yml (1 hunks)
  • helmfile-app/grafana-alloy/values.yaml.gotmpl (3 hunks)
  • helmfile-app/vars/secrets.yaml (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-28T22:08:40.542Z
Learnt from: wolf31o2
Repo: blinklabs-io/vpn-infrastructure PR: 51
File: .github/workflows/conventional-commits.yml:16-17
Timestamp: 2025-10-28T22:08:40.542Z
Learning: The webiny/action-conventional-commits GitHub Action reports commit message validation by exiting with a non-zero exit code (failing the job) rather than posting status updates via the GitHub API. Therefore, it only requires `contents: read` permission, not `checks: write` or `pull-requests: write`.

Applied to files:

  • .github/workflows/run-helmfile.yml
  • .github/workflows/pr-helmfile.yml
  • .github/workflows/test-helmfile.yml
  • .github/workflows/common-helmfile.yml
🔇 Additional comments (11)
helmfile-app/vars/secrets.yaml (1)

1-60: LGTM! Secrets properly encrypted with SOPS.

The grafana.password ciphertext has been updated along with the SOPS metadata (lastmodified and MAC), which is consistent with credential rotation. All secrets remain properly encrypted using SOPS with AES256_GCM and AWS KMS, ensuring no plaintext credentials are exposed in the repository.

.github/workflows/test-terraform.yml (1)

6-8: LGTM! Formatting improvement for readability.

The YAML formatting has been updated to use multi-line list syntax, which improves readability without changing the workflow's behavior.

helmfile-app/grafana-alloy/values.yaml.gotmpl (2)

47-49: LGTM! Credentials now sourced from environment variables.

Replacing hardcoded credentials with environment variable lookups (env("GRAFANA_USERNAME") and env("GRAFANA_PASSWORD")) improves security by enabling secret-based credential management.


155-165: LGTM! Proper injection of credentials from Kubernetes Secret.

The extraEnv block correctly injects Grafana credentials from the grafana-cloud Secret into the pod environment, ensuring credentials are not hardcoded in the configuration.

.github/workflows/pr-helmfile.yml (1)

1-21: LGTM! Well-structured workflow with proper permissions.

The workflow is well-designed with:

  • Minimal permissions (contents: read)
  • Path-based triggers to run only when relevant files change
  • Reusable workflow pattern for consistency
  • Matrix strategy for future extensibility
.github/workflows/run-helmfile.yml (1)

1-26: LGTM! Well-designed manual workflow with proper security controls.

The workflow is properly structured with:

  • Minimal permissions (contents: read)
  • Clear input definitions with descriptions and defaults
  • Type-safe choice input for cluster selection
  • Reusable workflow pattern for consistency
  • Secure secret inheritance
.github/workflows/test-helmfile.yml (1)

1-23: LGTM! Test workflow with proper security controls.

The workflow is well-structured with:

  • Minimal permissions (contents: read)
  • Clear cluster input definition
  • Hardcoded "diff" argument appropriate for testing
  • Reusable workflow pattern for consistency
.github/workflows/common-helmfile.yml (4)

1-67: LGTM! Well-secured reusable workflow with excellent security practices.

The workflow demonstrates strong security posture:

  • Minimal permissions (contents: read)
  • SHA-pinned action versions for supply chain security
  • Conditional AWS configuration based on cluster input
  • Secrets properly sourced from GitHub Secrets
  • Clean separation of concerns with reusable pattern

17-17: Clarify runner choice: ubuntu-latest vs self-hosted.

The workflow uses ubuntu-latest as the runner, but a past review comment from @agaffney asked "Why self-hosted?" This suggests there may have been an expectation or requirement to use self-hosted runners. Please clarify:

  1. Is ubuntu-latest (GitHub-hosted) acceptable for this workflow?
  2. Are there networking, access, or compliance requirements that would necessitate self-hosted runners?
  3. Do the AWS credentials and EKS cluster access work correctly from GitHub-hosted runners?

35-51: AWS CLI installation script is well-written.

The installation script properly:

  • Checks if AWS CLI already exists to avoid redundant installs
  • Downloads from the official AWS source
  • Installs to user directory to avoid permission issues
  • Updates $GITHUB_PATH correctly
  • Cleans up temporary files

66-66: Verification Complete: Helmfile environment configuration is correct.

The Helmfile configuration in helmfile-app/helmfile-defaults.yaml.gotmpl defines environments that match cluster names (e.g., aws-vpn, local-vpn, default). The workflow's use of -e ${{ inputs.cluster }} is the correct Helmfile syntax for selecting the target environment. No issues found.

Comment on lines 4 to 6
paths:
- "helmfile-app/**"
- ".github/workflows/test-helmfile.yml"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify the path filter reference.

Line 6 references .github/workflows/test-helmfile.yml, but this workflow file is pr-helmfile.yml. Did you intend to reference .github/workflows/pr-helmfile.yml instead? If this workflow should trigger when test-helmfile.yml changes, please clarify the reasoning.

Run the following script to check the relationship between these workflow files:


🏁 Script executed:

#!/bin/bash
# Check if test-helmfile.yml references pr-helmfile.yml or if this is a typo
echo "=== Checking pr-helmfile.yml paths trigger ==="
grep -n "paths:" .github/workflows/pr-helmfile.yml -A5

echo -e "\n=== Checking if test-helmfile.yml and pr-helmfile.yml share common patterns ==="
if [ -f .github/workflows/test-helmfile.yml ]; then
  echo "test-helmfile.yml exists"
  grep -n "uses:" .github/workflows/test-helmfile.yml
  grep -n "uses:" .github/workflows/pr-helmfile.yml
else
  echo "test-helmfile.yml not found"
fi

Length of output: 384


I need to examine the full content and purpose of both workflow files to understand if this cross-reference is intentional.


---

🏁 Script executed:

```shell
#!/bin/bash
# Get full content of both workflow files to understand their purposes
echo "=== Full pr-helmfile.yml ==="
cat .github/workflows/pr-helmfile.yml

echo -e "\n=== Full test-helmfile.yml ==="
cat .github/workflows/test-helmfile.yml

Length of output: 864


Update line 6 to reference .github/workflows/pr-helmfile.yml instead of test-helmfile.yml.

The current path trigger references test-helmfile.yml, which is a manual-only workflow (triggered via workflow_dispatch). The pr-helmfile.yml workflow should retrigger when changes are made to itself, not to the separate manual workflow. Update the path filter to reference .github/workflows/pr-helmfile.yml.

🤖 Prompt for AI Agents
.github/workflows/pr-helmfile.yml lines 4-6: the path filter currently
references ".github/workflows/test-helmfile.yml" but should reference the
workflow file itself so changes to pr-helmfile.yml retrigger the workflow; edit
line 6 to change the path to ".github/workflows/pr-helmfile.yml" (replace
test-helmfile.yml with pr-helmfile.yml) so the workflow is triggered on edits to
its own file.

@verbotenj verbotenj force-pushed the feat/add-gha branch 2 times, most recently from 949bae4 to 0225f87 Compare November 4, 2025 16:31
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
.github/workflows/common-helmfile.yml (1)

38-54: Consider using an established AWS CLI installation action.

The custom bash script for installing AWS CLI v2 works, but using a maintained action (e.g., unfor19/install-aws-cli-action) would reduce maintenance burden and improve consistency across workflows. The current approach is functional and safe, but worth considering as a refactor.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0225f87 and 5c4a696.

📒 Files selected for processing (7)
  • .github/workflows/common-helmfile.yml (1 hunks)
  • .github/workflows/pr-helmfile.yml (1 hunks)
  • .github/workflows/run-helmfile.yml (1 hunks)
  • .github/workflows/test-helmfile.yml (1 hunks)
  • .github/workflows/test-terraform.yml (1 hunks)
  • helmfile-app/grafana-alloy/values.yaml.gotmpl (3 hunks)
  • helmfile-app/vars/secrets.yaml (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • .github/workflows/run-helmfile.yml
  • .github/workflows/test-helmfile.yml
  • helmfile-app/vars/secrets.yaml
  • .github/workflows/pr-helmfile.yml
  • .github/workflows/test-terraform.yml
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-28T22:08:40.542Z
Learnt from: wolf31o2
Repo: blinklabs-io/vpn-infrastructure PR: 51
File: .github/workflows/conventional-commits.yml:16-17
Timestamp: 2025-10-28T22:08:40.542Z
Learning: The webiny/action-conventional-commits GitHub Action reports commit message validation by exiting with a non-zero exit code (failing the job) rather than posting status updates via the GitHub API. Therefore, it only requires `contents: read` permission, not `checks: write` or `pull-requests: write`.

Applied to files:

  • .github/workflows/common-helmfile.yml
🔇 Additional comments (6)
.github/workflows/common-helmfile.yml (4)

11-12: Permissions block properly configured.

The permissions: contents: read is appropriate for this reusable workflow and aligns with the learnings on minimal permission scoping. This addresses the prior security finding.


19-29: All third-party actions are correctly pinned to commit hashes.

Every action uses a full commit SHA, not just a semantic version tag, which prevents unexpected behavior from upstream changes. This addresses the prior finding regarding the mozilla-sops-action.


30-36: AWS credentials properly sourced from GitHub Secrets.

The workflow uses ${{ secrets.VPN_OPS_AWS_ACCESS_KEY_ID }} and ${{ secrets.VPN_OPS_AWS_SECRET_ACCESS_KEY }}, which prevents credential exposure in logs and aligns with the PR objective of storing sensitive data only in Secret resources.


60-70: No action required—helmfile workspace is properly configured.

The helmfile-app directory contains all necessary dependencies and configuration files. The main configuration exists as helmfile.yaml.gotmpl (a Go template form), which correctly includes helmfile-defaults.yaml.gotmpl and helmfile-repos.yaml. The .sops.yaml file is present with AWS KMS encryption configured for the helm-secrets plugin. Variables and secrets are pre-loaded via the environments configuration. The helmfile-auto-init: "false" setting is appropriate and correctly aligned with this pre-configured environment—no automatic initialization is needed.

helmfile-app/grafana-alloy/values.yaml.gotmpl (2)

47-48: LGTM! Environment variable pattern is secure.

Using env() to reference credentials prevents them from being logged or exposed in the configuration. This aligns well with the PR objective of keeping secrets out of workflow logs.


155-165: LGTM! Proper Kubernetes Secret injection pattern.

The extraEnv configuration correctly injects credentials from the grafana-cloud Secret as environment variables, following Kubernetes best practices.

Signed-off-by: Ales Verbic <[email protected]>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
helmfile-app/grafana-alloy/values.yaml.gotmpl (1)

167-175: Move hardcoded username to SOPS-encrypted secrets file.

Line 174 contains the Grafana username "1834751" in plaintext, which violates the PR objective: "Ensure no secrets are exposed in repository files or workflow logs (nothing secret outside Secret resources)."

While the password correctly uses a template from the SOPS-encrypted secrets.yaml, the username should follow the same pattern for consistency and defense-in-depth.

Apply this diff to reference the username from encrypted values:

   stringData:
-    GRAFANA_USERNAME: "1834751"
+    GRAFANA_USERNAME: "{{ .Values.grafana.username }}"
     GRAFANA_PASSWORD: "{{ .Values.grafana.password }}"

Then add grafana.username to the SOPS-encrypted helmfile-app/vars/secrets.yaml file alongside the existing grafana.password.

🧹 Nitpick comments (1)
.github/workflows/common-helmfile.yml (1)

19-28: Fix typo in kubectl setup comment.

All actions are properly pinned to commit hashes, which is excellent for security. However, there's a minor typo in the version comment.

Apply this diff to fix the typo:

       - name: Install kubectl
-        uses: azure/setup-kubectl@0c5e050edfed71b2b50731ab044d42489d51c129 # vv4.0.0 https://github.com/Azure/setup-kubectl/releases/tag/vv4.0.0
+        uses: azure/setup-kubectl@0c5e050edfed71b2b50731ab044d42489d51c129 # v4.0.0 https://github.com/Azure/setup-kubectl/releases/tag/v4.0.0
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5c4a696 and 9e5cbd2.

📒 Files selected for processing (7)
  • .github/workflows/common-helmfile.yml (1 hunks)
  • .github/workflows/pr-helmfile.yml (1 hunks)
  • .github/workflows/run-helmfile.yml (1 hunks)
  • .github/workflows/test-helmfile.yml (1 hunks)
  • .github/workflows/test-terraform.yml (1 hunks)
  • helmfile-app/grafana-alloy/values.yaml.gotmpl (3 hunks)
  • helmfile-app/vars/secrets.yaml (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • .github/workflows/test-helmfile.yml
  • .github/workflows/run-helmfile.yml
  • .github/workflows/pr-helmfile.yml
  • helmfile-app/vars/secrets.yaml
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-28T22:08:40.542Z
Learnt from: wolf31o2
Repo: blinklabs-io/vpn-infrastructure PR: 51
File: .github/workflows/conventional-commits.yml:16-17
Timestamp: 2025-10-28T22:08:40.542Z
Learning: The webiny/action-conventional-commits GitHub Action reports commit message validation by exiting with a non-zero exit code (failing the job) rather than posting status updates via the GitHub API. Therefore, it only requires `contents: read` permission, not `checks: write` or `pull-requests: write`.

Applied to files:

  • .github/workflows/common-helmfile.yml
🔇 Additional comments (8)
.github/workflows/test-terraform.yml (1)

6-8: LGTM: Formatting update.

The trigger formatting changes are cosmetic and semantically equivalent to the previous version.

helmfile-app/grafana-alloy/values.yaml.gotmpl (2)

47-48: LGTM: Proper credential referencing.

Using env() to read credentials from environment variables is the correct approach for Grafana Alloy configuration.


155-165: LGTM: Proper environment variable injection.

The extraEnv configuration correctly injects environment variables from the grafana-cloud Secret using Kubernetes-native secretKeyRef.

.github/workflows/common-helmfile.yml (5)

1-13: LGTM: Proper reusable workflow setup.

The workflow is correctly configured as reusable with workflow_call, required inputs, and minimal permissions (contents: read). This addresses the previous code scanning alert about missing permissions.


30-46: LGTM: Secure AWS credentials handling.

AWS credentials are correctly sourced from GitHub Secrets and conditionally configured only for the aws-vpn cluster. The use of heredoc syntax prevents injection issues.


47-64: LGTM: Robust AWS CLI installation.

The installation script correctly:

  • Checks if AWS CLI is already available before installing
  • Uses the official AWS CLI v2 installer
  • Installs to a local directory (appropriate for GitHub Actions)
  • Handles PATH manipulation for subsequent steps
  • Uses set -e for proper error handling

65-67: LGTM: EKS kubeconfig setup.

The EKS configuration correctly updates kubeconfig for the specified cluster and is appropriately conditional on the aws-vpn cluster input.


69-79: LGTM: Well-configured Helmfile execution.

The Helmfile step is properly configured with:

  • Pinned action version for security
  • Explicit Helmfile and Helm versions for reproducibility
  • Required plugins (helm-diff and helm-secrets) for the workflow
  • Correct working directory and argument passing

@verbotenj verbotenj merged commit ec786b4 into main Nov 6, 2025
7 checks passed
@verbotenj verbotenj deleted the feat/add-gha branch November 6, 2025 18:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

GHA workflows for CI / CD

4 participants