Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
b62b9e5
Add design document for stack removal detection feature
owine Dec 3, 2025
2e5bd57
Add .worktrees/ to .gitignore
owine Dec 3, 2025
93b4475
feat: add stack removal detection and cleanup step
owine Dec 4, 2025
283cbc4
feat: add Discord notification for removed stack cleanup
owine Dec 4, 2025
1bc8953
feat: expose removed stacks as job outputs
owine Dec 4, 2025
fdec08e
fix: skip removal detection on first deployment
owine Dec 5, 2025
2fb4d32
feat: add robust error handling for git diff
owine Dec 5, 2025
1651ef2
docs: add inline documentation for stack removal cleanup
owine Dec 5, 2025
5a0c1f6
docs: document stack removal cleanup feature
owine Dec 5, 2025
274fbbe
fix: address code review feedback
owine Dec 5, 2025
2a11a86
fix: properly pass variables to remote SSH commands
owine Dec 5, 2025
34685eb
fix: make heredoc pattern robust and fix log group closure
owine Dec 5, 2025
8e08f1d
fix: improve security and JSON handling
owine Dec 5, 2025
4aee86b
fix: quote JSON variable and revert to embedded token
owine Dec 6, 2025
4ef9cf8
docs: add script extraction proposal for stack removal
owine Dec 6, 2025
ce08d83
refactor: improve stack removal code organization and fix shellcheck …
owine Dec 6, 2025
c0959de
security: pass OP token via stdin instead of command-line args
owine Dec 6, 2025
e866abe
feat: add actionlint for GitHub Actions workflow validation
owine Dec 6, 2025
eed5c3d
fix: resolve shellcheck warnings in lint workflow
owine Dec 6, 2025
f7966d3
feat: add actionlint workflow validation to lint.yml
owine Dec 6, 2025
030a992
fix: correct OP token passing mechanism in cleanup_stack function
owine Dec 6, 2025
6f3b5f7
fix: correct OP token expansion and grammar in step names
owine Dec 6, 2025
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
305 changes: 272 additions & 33 deletions .github/workflows/deploy.yml

Large diffs are not rendered by default.

71 changes: 61 additions & 10 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,20 @@ jobs:
with:
unset-previous: true

actionlint:
name: Workflow validation
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- name: Checkout target repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
repository: ${{ inputs.target-repository }}
ref: ${{ inputs.target-ref }}

- name: Run actionlint
uses: raven-actions/actionlint@v2.0.1

lint:
strategy:
matrix:
Expand Down Expand Up @@ -154,7 +168,10 @@ jobs:
local temp_env_file="$2"

# Extract environment variable references from compose file and create realistic placeholders
grep -oE '\$\{[^}]+\}' "$compose_file" | sort -u | sed 's/\${//' | sed 's/}//' | while read var; do
while IFS= read -r match; do
# Remove ${ prefix and } suffix using parameter expansion
var="${match#\$\{}"
var="${var%\}}"
# Use realistic placeholder values based on common variable patterns
case "$var" in
*PATH*|*DIR*)
Expand Down Expand Up @@ -185,7 +202,7 @@ jobs:
echo "${var}=placeholder_value" >> "$temp_env_file"
;;
esac
done 2>/dev/null || true
done < <(grep -oE '\$\{[^}]+\}' "$compose_file" | sort -u) 2>/dev/null || true
}

# Run YAML and Docker Compose linting in parallel with output capture
Expand Down Expand Up @@ -234,7 +251,7 @@ jobs:
echo "❌ FAILED - YAML linting detected issues in ./${{ matrix.stack }}/compose.yaml:"
echo ""
echo "🔍 Issues found:"
cat "$YAML_OUTPUT" | sed 's/^/ /' | sed 's|\.\/||g'
sed 's/^/ /' "$YAML_OUTPUT" | sed 's|\.\/||g'
echo ""
echo "🛠️ Fix locally with:"
echo " yamllint --strict --config-file .yamllint ${{ matrix.stack }}/compose.yaml"
Expand All @@ -253,7 +270,7 @@ jobs:
echo "🔍 Issues found:"
# Use filtered output to show relevant errors
if [ -s "$DOCKER_FILTERED" ]; then
cat "$DOCKER_FILTERED" | sed 's/^/ /'
sed 's/^/ /' "$DOCKER_FILTERED"
else
echo " Configuration errors detected (see full output above)"
fi
Expand Down Expand Up @@ -308,7 +325,7 @@ jobs:
lint-summary:
name: Lint Summary
runs-on: ubuntu-24.04
needs: [scanning, lint]
needs: [scanning, actionlint, lint]
if: always()
timeout-minutes: 5
steps:
Expand All @@ -326,7 +343,10 @@ jobs:
local temp_env_file="$2"

# Extract environment variable references from compose file and create realistic placeholders
grep -oE '\$\{[^}]+\}' "$compose_file" | sort -u | sed 's/\${//' | sed 's/}//' | while read var; do
while IFS= read -r match; do
# Remove ${ prefix and } suffix using parameter expansion
var="${match#\$\{}"
var="${var%\}}"
# Use realistic placeholder values based on common variable patterns
case "$var" in
*PATH*|*DIR*)
Expand Down Expand Up @@ -357,7 +377,7 @@ jobs:
echo "${var}=placeholder_value" >> "$temp_env_file"
;;
esac
done 2>/dev/null || true
done < <(grep -oE '\$\{[^}]+\}' "$compose_file" | sort -u) 2>/dev/null || true
}

echo "📊 Final Validation Summary"
Expand Down Expand Up @@ -390,6 +410,26 @@ jobs:

echo ""

# Actionlint Workflow Validation Results
echo "⚙️ WORKFLOW VALIDATION (ACTIONLINT)"
echo "───────────────────────────────────────────────────────────────────────────────────"
case "${{ needs.actionlint.result }}" in
"success")
echo "✅ PASSED - All GitHub Actions workflows are valid"
ACTIONLINT_OK=true
;;
"failure")
echo "❌ FAILED - Workflow validation issues detected"
ACTIONLINT_OK=false
;;
*)
echo "❓ UNKNOWN - Unexpected actionlint result: ${{ needs.actionlint.result }}"
ACTIONLINT_OK=false
;;
esac

echo ""

# Detailed Lint Results with Error Reproduction
echo "📋 CODE QUALITY VALIDATION - DETAILED RESULTS"
echo "───────────────────────────────────────────────────────────────────────────────────"
Expand Down Expand Up @@ -422,6 +462,7 @@ jobs:
else
echo " ❌ FAILED - YAML validation detected issues:"
echo ""
# shellcheck disable=SC2001 # sed is appropriate for multi-line prefix addition
yamllint --strict --config-file .yamllint "./$stack/compose.yaml" 2>&1 | sed 's/^/ /' | sed 's|\.\/||g'
echo ""
echo " 🛠️ Fix locally: yamllint --strict --config-file .yamllint $stack/compose.yaml"
Expand All @@ -447,7 +488,8 @@ jobs:
grep -v "WARNING.*not set" || echo "Configuration errors detected")

if [[ -n "$DOCKER_ERRORS" && "$DOCKER_ERRORS" != "Configuration errors detected" ]]; then
echo "$DOCKER_ERRORS" | sed 's/^/ /'
# shellcheck disable=SC2001 # sed is appropriate for multi-line prefix addition
sed 's/^/ /' <<< "$DOCKER_ERRORS"
else
echo " Configuration syntax or structure issues detected"
fi
Expand Down Expand Up @@ -505,7 +547,7 @@ jobs:
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"

# Final determination
if [[ "$SCANNING_OK" == "true" && "$LINT_OK" == "true" ]]; then
if [[ "$SCANNING_OK" == "true" && "$ACTIONLINT_OK" == "true" && "$LINT_OK" == "true" ]]; then
echo "🎉 FINAL STATUS: ALL VALIDATION CHECKS PASSED"
echo " Repository is ready for deployment"
exit 0
Expand All @@ -515,6 +557,7 @@ jobs:
echo ""
echo " Failed components:"
[[ "$SCANNING_OK" != "true" ]] && echo " • GitGuardian security scanning"
[[ "$ACTIONLINT_OK" != "true" ]] && echo " • Workflow validation (actionlint)"
[[ "$LINT_OK" != "true" ]] && echo " • Code quality validation (see detailed errors above)"
echo ""
exit 1
Expand All @@ -523,7 +566,7 @@ jobs:
notify:
name: Discord Notification
runs-on: ubuntu-24.04
needs: [scanning, lint, lint-summary]
needs: [scanning, actionlint, lint, lint-summary]
if: always()
steps:
- name: Configure 1Password Service Account
Expand Down Expand Up @@ -551,12 +594,20 @@ jobs:
${{ needs.lint-summary.result == 'failure' && inputs.discord-user-id != '' && steps.op-load-discord.outputs.DISCORD_USER_ID != 'SKIP' && format('<@{0}> ', steps.op-load-discord.outputs.DISCORD_USER_ID) || '' }}${{ needs.lint-summary.result == 'success' && '✅ **All validation checks passed**' || '❌ **Validation issues detected**' }}

**🔒 Security Scan:** ${{ needs.scanning.result == 'success' && '✅ No secrets detected' || needs.scanning.result == 'skipped' && '⏭️ Skipped (PR/manual)' || '❌ Issues found' }}
**⚙️ Workflow Validation:** ${{ needs.actionlint.result == 'success' && '✅ All workflows valid' || '❌ Issues detected' }}
**📋 Code Quality:** ${{ needs.lint.result == 'success' && '✅ All stacks valid' || '❌ Issues detected' }}

**📂 Validated Stacks:** `${{ join(fromJson(inputs.stacks), '`, `') }}`

${{ github.event_name == 'pull_request' && '🔀 **Pull Request Validation**' || github.event_name == 'workflow_dispatch' && '🔧 **Manual Validation**' || format('📝 **Push to `{0}`**', github.ref_name) }}

${{ needs.actionlint.result == 'failure' && '
**⚙️ Workflow Issues:**
• GitHub Actions workflow validation failed
• Review the **Workflow Validation** job for details
• Fix workflow syntax, shellcheck, or expression errors
• Test locally: `actionlint .github/workflows/*.yml`' || '' }}

${{ needs.lint.result == 'failure' && '
**🚨 Action Required:**
• Review stack validation errors in workflow logs
Expand Down
17 changes: 15 additions & 2 deletions .github/workflows/yamllint.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: YAML Lint
name: Lint Workflows

on:
push:
Expand All @@ -16,14 +16,27 @@ jobs:
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1

- name: Run yamllint
id: yamllint
continue-on-error: true
run: yamllint --strict --config-file .yamllint .

- name: Report results
if: always()
run: |
if [ $? -eq 0 ]; then
if [ "${{ steps.yamllint.outcome }}" = "success" ]; then
echo "✅ All YAML files are properly formatted"
else
echo "❌ YAML formatting issues found"
echo "Please fix the issues above or update .yamllint configuration if needed"
exit 1
fi

actionlint:
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- name: Checkout repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1

- name: Run actionlint
uses: raven-actions/actionlint@v2.0.1
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,7 @@ package-lock.json
yarn.lock

# GitHub Actions runner temp files
.runner/
.runner/

# Git worktrees
.worktrees/
2 changes: 2 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ This repository provides two main reusable workflows:
5. **Caching Strategies**: Optimized caching for Tailscale state and deployment tools
6. **SSH Optimization**: Connection multiplexing and retry mechanisms
7. **Parallel Execution**: All lint jobs (GitGuardian, YAML lint) run concurrently
8. **Stack Removal Detection**: Automatic cleanup of removed stacks with fail-safe operation

### Benefits of Centralization

Expand Down Expand Up @@ -175,6 +176,7 @@ The deploy workflow (`deploy.yml`) provides:
8. **SSH Optimization** - Connection multiplexing for better performance
9. **Caching** - Optimized caching for Tailscale and deployment tools
10. **Rich Discord Notifications** - Comprehensive deployment status with health metrics
11. **Stack Removal Cleanup** - Detect deleted stacks via git diff and clean up containers before repository update

## Security Integration

Expand Down
Loading