Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .claude/commands/composite.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ Before writing custom steps from scratch, search the [Marketplace](https://githu

- Prefer a well-maintained marketplace action over custom shell scripting for non-trivial logic
- Wrap it in a composite if it needs input normalization or additional steps
- Pin to a specific tag or SHA — never `@main` or `@master`
- **Third-party actions (outside `LerianStudio` org) must be pinned by commit SHA**, not by tag — add a `# vX.Y.Z` comment for readability (e.g., `uses: actions/checkout@abc123 # v6`). Tags are mutable and can be force-pushed by upstream maintainers. Dependabot proposes SHA bumps automatically.
- `LerianStudio/*` actions are pinned by **release tag** (`@v1.2.3`) or branch (`@develop` for testing)
- Never use `@main` or `@master` for third-party actions
- Document in the composite `README.md` why that action was chosen

Only implement from scratch when no suitable action exists or when existing ones don't meet security or customization requirements.
Expand Down
15 changes: 13 additions & 2 deletions .claude/commands/gha.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,9 @@ Before writing custom steps from scratch, search the [Marketplace](https://githu

- Prefer a well-maintained marketplace action over custom shell scripting for non-trivial logic
- If the action needs wrapping, create a composite in `src/` — don't inline complex shell directly in a workflow
- Pin to a specific tag or SHA — never `@main` or `@master`
- **Third-party actions (outside `LerianStudio` org) must be pinned by commit SHA**, not by tag — add a comment with the version for readability (e.g., `uses: actions/checkout@abc123 # v6`). Tags are mutable and can be force-pushed by upstream maintainers. Dependabot will propose SHA bumps automatically.
- `LerianStudio/*` actions are pinned by **release tag** (e.g., `@v1.2.3`) or branch (`@develop` for testing)
- Never use `@main` or `@master` for third-party actions
- Document in the README or `docs/` why that action was chosen

Only implement from scratch when no suitable action exists or when existing ones don't meet security or customization requirements.
Expand Down Expand Up @@ -466,11 +468,20 @@ uses: ./src/setup-go # resolves to caller's workspace, not this repo

# ❌ Mutable ref on third-party actions
uses: some-action/tool@main

# ❌ Third-party action pinned by tag (tags are mutable)
uses: actions/checkout@v6
uses: crazy-max/ghaction-import-gpg@v7

# ✅ Third-party action pinned by commit SHA
uses: actions/checkout@abc123def456 # v6
uses: crazy-max/ghaction-import-gpg@2dc316deee8e # v7
```

## Security rules

- Pin all third-party actions to a specific tag or SHA — Dependabot keeps them updated
- **Third-party actions (outside `LerianStudio` org) must be pinned by commit SHA** — tags are mutable and can be force-pushed. Add a `# vX.Y.Z` comment for readability. Dependabot keeps SHA pins updated automatically.
- `LerianStudio/*` actions use release tags (`@v1.2.3`) — no SHA pinning needed for org-owned actions
- Never use `@main` or `@master` for third-party actions
- Never interpolate untrusted user input directly into `run:` commands
- Never print secrets via `echo`, env dumps, or step summaries
Expand Down
13 changes: 11 additions & 2 deletions .claude/commands/workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ Before implementing custom steps inside a workflow, search the [Marketplace](htt

- Prefer a well-maintained action over custom shell scripting for non-trivial logic
- If the action needs wrapping (normalization, extra steps), create a composite in `src/` and call it from the workflow — don't inline complex shell in the workflow itself
- Pin to a specific tag or SHA — never `@main` or `@master`
- **Third-party actions (outside `LerianStudio` org) must be pinned by commit SHA**, not by tag — add a `# vX.Y.Z` comment for readability (e.g., `uses: actions/checkout@abc123 # v6`). Tags are mutable and can be force-pushed by upstream maintainers. Dependabot proposes SHA bumps automatically.
- `LerianStudio/*` actions are pinned by **release tag** (`@v1.2.3`) or branch (`@develop` for testing)
- Never use `@main` or `@master` for third-party actions
- Document in `docs/<workflow-name>.md` why that action was chosen

Only implement from scratch when no suitable action exists or when existing ones don't meet security or customization requirements.
Expand Down Expand Up @@ -340,11 +342,18 @@ uses: ./src/setup-go # resolves to caller's workspace, not this repo

# ❌ Mutable ref on third-party actions
uses: some-action/tool@main

# ❌ Third-party action pinned by tag (tags are mutable)
uses: actions/checkout@v6

# ✅ Third-party action pinned by commit SHA
uses: actions/checkout@abc123def456 # v6
```

## Security rules

- Pin all third-party actions to a specific tag or SHA — Dependabot keeps them updated
- **Third-party actions (outside `LerianStudio` org) must be pinned by commit SHA** — tags are mutable and can be force-pushed. Add a `# vX.Y.Z` comment for readability. Dependabot keeps SHA pins updated automatically.
- `LerianStudio/*` actions use release tags (`@v1.2.3`) — no SHA pinning needed for org-owned actions
- Never use `@main` or `@master` for third-party actions
- Never interpolate untrusted user input directly into `run:` commands
- Never print secrets via `echo`, env dumps, or step summaries
Expand Down
4 changes: 3 additions & 1 deletion .cursor/rules/composite-actions.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ Before writing custom steps from scratch, search the [Marketplace](https://githu

- Prefer a well-maintained marketplace action over custom shell scripting for non-trivial logic
- Wrap it in a composite if it needs input normalization or additional steps
- Pin to a specific tag or SHA — never `@main` or `@master`
- **Third-party actions (outside `LerianStudio` org) must be pinned by commit SHA**, not by tag — add a `# vX.Y.Z` comment for readability (e.g., `uses: actions/checkout@abc123 # v6`). Tags are mutable and can be force-pushed by upstream maintainers. Dependabot proposes SHA bumps automatically.
- `LerianStudio/*` actions are pinned by **release tag** (`@v1.2.3`) or branch (`@develop` for testing)
- Never use `@main` or `@master` for third-party actions
- Document in the composite `README.md` why that action was chosen

Only implement from scratch when no suitable action exists or when existing ones don't meet security or customization requirements.
Expand Down
7 changes: 5 additions & 2 deletions .cursor/rules/reusable-workflows.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ Before implementing custom steps inside a workflow, search the [Marketplace](htt

- Prefer a well-maintained action over custom shell scripting for non-trivial logic
- If the action needs wrapping (normalization, extra steps), create a composite in `src/` and call it from the workflow — don't inline complex shell in the workflow itself
- Pin to a specific tag or SHA — never `@main` or `@master`
- **Third-party actions (outside `LerianStudio` org) must be pinned by commit SHA**, not by tag — add a `# vX.Y.Z` comment for readability (e.g., `uses: actions/checkout@abc123 # v6`). Tags are mutable and can be force-pushed by upstream maintainers. Dependabot proposes SHA bumps automatically.
- `LerianStudio/*` actions are pinned by **release tag** (`@v1.2.3`) or branch (`@develop` for testing)
- Never use `@main` or `@master` for third-party actions
- Document in `docs/<workflow-name>.md` why that action was chosen

Only implement from scratch when no suitable action exists or when existing ones don't meet security or customization requirements.
Expand Down Expand Up @@ -408,7 +410,8 @@ uses: some-action/tool@main # use a specific tag or SHA

## Security rules

- Pin all third-party actions to a specific tag or SHA — Dependabot keeps them updated
- **Third-party actions (outside `LerianStudio` org) must be pinned by commit SHA** — tags are mutable and can be force-pushed. Add a `# vX.Y.Z` comment for readability. Dependabot keeps SHA pins updated automatically.
- `LerianStudio/*` actions use release tags (`@v1.2.3`) — no SHA pinning needed for org-owned actions
- Never use `@main` or `@master` for third-party actions
- Never interpolate untrusted user input directly into `run:` commands
- Never print secrets via `echo`, env dumps, or step summaries
Expand Down
93 changes: 51 additions & 42 deletions .github/workflows/helm-update-chart.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
name: "Update Helm Chart"

# Reusable workflow for updating Helm charts from dispatch payload
Expand Down Expand Up @@ -136,17 +136,22 @@
TIMESTAMP=$(date +%Y%m%d%H%M%S)
BRANCH_NAME="update/${CHART}/${SOURCE_REF}-${TIMESTAMP}"

echo "chart=${CHART}" >> $GITHUB_OUTPUT
echo "has_new_env_vars=${HAS_NEW_ENV_VARS}" >> $GITHUB_OUTPUT
echo "source_ref=${SOURCE_REF}" >> $GITHUB_OUTPUT
echo "source_repo=${SOURCE_REPO}" >> $GITHUB_OUTPUT
echo "source_actor=${SOURCE_ACTOR}" >> $GITHUB_OUTPUT
echo "source_sha=${SOURCE_SHA}" >> $GITHUB_OUTPUT
echo "branch_name=${BRANCH_NAME}" >> $GITHUB_OUTPUT
{
echo "chart=${CHART}"
echo "has_new_env_vars=${HAS_NEW_ENV_VARS}"
echo "source_ref=${SOURCE_REF}"
echo "source_repo=${SOURCE_REPO}"
echo "source_actor=${SOURCE_ACTOR}"
echo "source_sha=${SOURCE_SHA}"
echo "branch_name=${BRANCH_NAME}"
} >> "$GITHUB_OUTPUT"

# Save components array to file for processing
jq -c '.components' /tmp/payload.json > /tmp/components.json

# CodeQL: untrusted-checkout — false positive. This is a workflow_call
# triggered by internal dispatch, not a PR event. The ref is a controlled
# branch name (develop/main), not an untrusted PR head.
- name: Checkout
uses: actions/checkout@v6
with:
Expand All @@ -156,7 +161,7 @@

- name: Import GPG key
if: ${{ inputs.gpg_sign_commits }}
uses: crazy-max/ghaction-import-gpg@v7
uses: crazy-max/ghaction-import-gpg@2dc316deee8e90f13e1a351ab510b4d5bc0c82cd # v7

Check failure on line 164 in .github/workflows/helm-update-chart.yml

View workflow job for this annotation

GitHub Actions / Pinned Actions Check

Unpinned action found: uses: crazy-max/ghaction-import-gpg@2dc316deee8e90f13e1a351ab510b4d5bc0c82cd
with:
gpg_private_key: ${{ secrets.GPG_KEY }}
passphrase: ${{ secrets.GPG_KEY_PASSWORD }}
Expand Down Expand Up @@ -194,7 +199,7 @@
go build -o update-chart-version-readme update-chart-version-readme.go

- name: Setup yq
uses: mikefarah/yq@v4
uses: mikefarah/yq@5a7e72a743649b1b3a47d1a1d8214f3453173c51 # v4

Check failure on line 202 in .github/workflows/helm-update-chart.yml

View workflow job for this annotation

GitHub Actions / Pinned Actions Check

Unpinned action found: uses: mikefarah/yq@5a7e72a743649b1b3a47d1a1d8214f3453173c51

- name: Process all components
id: process
Expand Down Expand Up @@ -239,24 +244,22 @@
CHART_TEMPLATE_NAME=$(yq '.name' "${CHART_FILE}")

# Function to create secret template if it doesn't exist
# $1 = comp_name (for directory/file path)
# $2 = values_key (for .Values references)
# $1 = values_key (for directory/file path and .Values references)
create_secret_template() {
local comp_name="$1"
local values_key="${2:-$1}" # fallback to comp_name if not provided
local secret_file="${TEMPLATES_BASE}/${comp_name}/secret.yaml"
local values_key="$1"
local secret_file="${TEMPLATES_BASE}/${values_key}/secret.yaml"

if [ ! -f "$secret_file" ]; then
echo " Creating secret template: $secret_file"
mkdir -p "${TEMPLATES_BASE}/${comp_name}"
mkdir -p "${TEMPLATES_BASE}/${values_key}"
printf '%s\n' \
"apiVersion: v1" \
"kind: Secret" \
"metadata:" \
" name: {{ include \"${CHART_TEMPLATE_NAME}.fullname\" . }}-${comp_name}" \
" name: {{ include \"${CHART_TEMPLATE_NAME}.fullname\" . }}-${values_key}" \
" labels:" \
" {{- include \"${CHART_TEMPLATE_NAME}.labels\" . | nindent 4 }}" \
" app.kubernetes.io/component: ${comp_name}" \
" app.kubernetes.io/component: ${values_key}" \
"type: Opaque" \
"data:" \
" # Extra Secret Vars" \
Expand Down Expand Up @@ -295,10 +298,10 @@

# Add new environment variables if any
if [ "$COMP_ENV_VARS" != "{}" ] && [ "$COMP_ENV_VARS" != "null" ]; then
# Template paths use COMP_NAME (directory structure)
# Values references use VALUES_KEY (values.yaml structure)
CONFIGMAP_FILE="${TEMPLATES_BASE}/${COMP_NAME}/configmap.yaml"
SECRET_FILE="${TEMPLATES_BASE}/${COMP_NAME}/secret.yaml"
# Template paths use VALUES_KEY (directory structure matches values.yaml keys)
# Values references also use VALUES_KEY (values.yaml structure)
CONFIGMAP_FILE="${TEMPLATES_BASE}/${VALUES_KEY}/configmap.yaml"
SECRET_FILE="${TEMPLATES_BASE}/${VALUES_KEY}/secret.yaml"

echo "$COMP_ENV_VARS" | jq -r 'to_entries[] | "\(.key)=\(.value)"' | while IFS='=' read -r key value; do
if [ -n "$key" ]; then
Expand All @@ -309,19 +312,23 @@
if is_sensitive_var "$key"; then
echo " Adding SECRET var: ${key}=***"

# Create secret template if needed (uses COMP_NAME for path, VALUES_KEY for .Values)
create_secret_template "$COMP_NAME" "$VALUES_KEY"
# Create secret template if needed (uses VALUES_KEY for both path and .Values)
create_secret_template "$VALUES_KEY"

# Add to secret template (using 2 spaces indentation for data section)
if [ -f "${SECRET_FILE}" ] && grep -q "# Extra Secret Vars" "${SECRET_FILE}"; then
sed -i "/# Extra Secret Vars/i\\ ${key}: {{ .Values.${VALUES_KEY}.secrets.${key} | default \"${escaped_value}\" | b64enc | quote }}" "${SECRET_FILE}"
else
echo "::warning::Secret template not found or missing '# Extra Secret Vars' marker: ${SECRET_FILE} — skipping var ${key}"
fi
else
echo " Adding configmap var: ${key}=${value}"

# Add to configmap template if it exists (using 2 spaces indentation)
if [ -f "${CONFIGMAP_FILE}" ] && grep -q "# Extra Env Vars" "${CONFIGMAP_FILE}"; then
sed -i "/# Extra Env Vars/i\\ ${key}: {{ .Values.${VALUES_KEY}.configmap.${key} | default \"${escaped_value}\" | quote }}" "${CONFIGMAP_FILE}"
else
echo "::warning::Configmap template not found or missing '# Extra Env Vars' marker: ${CONFIGMAP_FILE} — skipping var ${key}"
fi
fi
fi
Expand All @@ -344,7 +351,7 @@
fi

echo ""
echo "updated_components=$UPDATED_COMPONENTS" >> $GITHUB_OUTPUT
echo "updated_components=${UPDATED_COMPONENTS}" >> "$GITHUB_OUTPUT"

- name: Update README matrix
if: ${{ inputs.update_readme }}
Expand Down Expand Up @@ -383,11 +390,11 @@
# Check if there are changes to commit
if git diff --staged --quiet; then
echo "No changes to commit"
echo "has_changes=false" >> $GITHUB_OUTPUT
echo "has_changes=false" >> "$GITHUB_OUTPUT"
exit 0
fi

echo "has_changes=true" >> $GITHUB_OUTPUT
echo "has_changes=true" >> "$GITHUB_OUTPUT"

# Determine commit message based on env_vars
# feat: when new environment variables are added (requires attention)
Expand All @@ -398,7 +405,7 @@
COMMIT_MSG="fix(${CHART}): update ${UPDATED_COMPONENTS}"
fi

echo "commit_msg=${COMMIT_MSG}" >> $GITHUB_OUTPUT
echo "commit_msg=${COMMIT_MSG}" >> "$GITHUB_OUTPUT"
echo "Committing with message: ${COMMIT_MSG}"
git commit -m "${COMMIT_MSG}"

Expand All @@ -407,7 +414,7 @@
if: steps.commit.outputs.has_changes == 'true'
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
run: |

Check failure on line 417 in .github/workflows/helm-update-chart.yml

View workflow job for this annotation

GitHub Actions / Action Lint

shellcheck reported issue in this script: SC2034:warning:4:1: COMMIT_MSG appears unused. Verify use (or export if used externally)
CHART="${{ steps.payload.outputs.chart }}"
BRANCH_NAME="${{ steps.payload.outputs.branch_name }}"
BASE_BRANCH="${{ inputs.base_branch }}"
Expand Down Expand Up @@ -463,35 +470,37 @@
--body-file /tmp/pr_body.md)

echo "PR created: ${PR_URL}"
echo "pr_url=${PR_URL}" >> $GITHUB_OUTPUT
echo "pr_url=${PR_URL}" >> "$GITHUB_OUTPUT"

- name: Summary
env:
BASE_BRANCH: ${{ inputs.base_branch }}
run: |

Check failure on line 478 in .github/workflows/helm-update-chart.yml

View workflow job for this annotation

GitHub Actions / Action Lint

shellcheck reported issue in this script: SC2129:style:6:1: Consider using { cmd1; cmd2; } >> file instead of individual redirects

Check failure on line 478 in .github/workflows/helm-update-chart.yml

View workflow job for this annotation

GitHub Actions / Action Lint

shellcheck reported issue in this script: SC2129:style:19:1: Consider using { cmd1; cmd2; } >> file instead of individual redirects
COMPONENTS=$(cat /tmp/components.json)
CHART="${{ steps.payload.outputs.chart }}"
BRANCH_NAME="${{ steps.payload.outputs.branch_name }}"
HAS_CHANGES="${{ steps.commit.outputs.has_changes }}"

echo "### Helm Chart Update Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Chart:** \`${CHART}\`" >> $GITHUB_STEP_SUMMARY
echo "**Branch:** \`${BRANCH_NAME}\`" >> $GITHUB_STEP_SUMMARY
echo "**Base:** \`${{ inputs.base_branch }}\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Helm Chart Update Summary" >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"
echo "**Chart:** \`${CHART}\`" >> "$GITHUB_STEP_SUMMARY"
echo "**Branch:** \`${BRANCH_NAME}\`" >> "$GITHUB_STEP_SUMMARY"
echo "**Base:** \`${BASE_BRANCH}\`" >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"

if [ "${HAS_CHANGES}" = "true" ]; then
echo "✅ **PR created successfully**" >> $GITHUB_STEP_SUMMARY
echo "✅ **PR created successfully**" >> "$GITHUB_STEP_SUMMARY"
else
echo "ℹ️ **No changes detected**" >> $GITHUB_STEP_SUMMARY
echo "ℹ️ **No changes detected**" >> "$GITHUB_STEP_SUMMARY"
fi

echo "" >> $GITHUB_STEP_SUMMARY
echo "**Components:**" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Component | Version | New Env Vars |" >> $GITHUB_STEP_SUMMARY
echo "|-----------|---------|--------------|" >> $GITHUB_STEP_SUMMARY
echo "" >> "$GITHUB_STEP_SUMMARY"
echo "**Components:**" >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"
echo "| Component | Version | New Env Vars |" >> "$GITHUB_STEP_SUMMARY"
echo "|-----------|---------|--------------|" >> "$GITHUB_STEP_SUMMARY"

echo "$COMPONENTS" | jq -r '.[] | "| \(.name) | \(.version) | \(.env_vars | if . == {} then "-" else (. | keys | join(", ")) end) |"' >> $GITHUB_STEP_SUMMARY
echo "$COMPONENTS" | jq -r '.[] | "| \(.name) | \(.version) | \(.env_vars | if . == {} then "-" else (. | keys | join(", ")) end) |"' >> "$GITHUB_STEP_SUMMARY"

- name: Send Slack notification
if: ${{ inputs.slack_notification && steps.commit.outputs.has_changes == 'true' }}
Expand Down
8 changes: 8 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,14 @@ Before modifying any existing file, follow the refactoring protocol in `.cursor/

## Security rules

- **Third-party actions (outside `LerianStudio` org) must be pinned by commit SHA**, not by tag — tags are mutable and can be force-pushed by upstream maintainers. Add a `# vX.Y.Z` comment for readability. Dependabot keeps SHA pins updated automatically.
```yaml
uses: actions/checkout@abc123def456 # v6 # ✅ third-party pinned by SHA
uses: crazy-max/ghaction-import-gpg@2dc316d # v7 # ✅ third-party pinned by SHA
uses: LerianStudio/github-actions-shared-workflows/src/notify/discord-release@v1.2.3 # ✅ org-owned pinned by tag
```
- `LerianStudio/*` actions use release tags (`@v1.2.3`) or branches (`@develop` for testing) — no SHA pinning needed for org-owned actions
- Never use `@main` or `@master` for third-party actions
- Never hardcode tokens, org names, or internal URLs — use `inputs` or `secrets`
- Never print secrets via `echo`, `run` output, or step summaries
- Vulnerability reports go through private channels only — see [`SECURITY.md`](SECURITY.md)
Loading