
Devops Automator
- 149 installs
- 178 repo stars
- Updated July 14, 2026
- erichowens/some_claude_skills
Automate repetitive DevOps chores—pipelines, environments, releases, and infra glue—so shipping stays fast, repeatable, and less error-prone across services.
About
devops-automator is for operators and full-stack builders who want Claude to draft and refine deployment automation instead of clicking through consoles. It fits tasks like composing GitHub Actions or similar pipelines, packaging services, wiring secrets, templating Terraform or shell deploy scripts, and standardizing staging-to-prod promotion. Expect opinionated, production-minded suggestions aimed at shrinking toil while keeping observability and safe rollback paths explicit.
- Turns manual release steps into scripted workflows
- Scaffolds CI/CD jobs, hooks, and environment promotion
- Reduces config drift across staging and production
- Encodes rollback, health checks, and deploy guardrails
- Speeds routine platform maintenance for small teams
Devops Automator by the numbers
- 149 all-time installs (skills.sh)
- Ranked #456 of 1,435 DevOps & CI/CD skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/erichowens/some_claude_skills --skill devops-automatorAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 149 |
|---|---|
| repo stars | ★ 178 |
| Last updated | July 14, 2026 |
| Repository | erichowens/some_claude_skills ↗ |
What it does
Automate repetitive DevOps chores—pipelines, environments, releases, and infra glue—so shipping stays fast, repeatable, and less error-prone across services.
Files
DevOps Automator
Expert DevOps engineer specializing in CI/CD pipelines, infrastructure as code, container orchestration, and deployment automation.
Activation Triggers
Activate on: "CI/CD", "GitHub Actions", "deployment pipeline", "Terraform", "infrastructure as code", "IaC", "Docker", "Kubernetes", "K8s", "Helm", "container orchestration", "GitOps", "ArgoCD", "deployment automation", "secrets management", "monitoring setup"
NOT for: Application development → language skills | Database design → data-pipeline-engineer | API design → api-architect
Quick Start
1. Define deployment strategy: Blue/Green, Canary, or Rolling 2. Choose IaC tool: Terraform for cloud resources, Helm for K8s apps 3. Design CI stages: lint → test → security scan → build → deploy 4. Implement GitOps: Config repo synced by ArgoCD 5. Add observability: Prometheus metrics, structured logging
Core Capabilities
| Domain | Tools & Technologies |
|---|---|
| CI/CD | GitHub Actions, GitLab CI, Jenkins |
| IaC | Terraform, AWS CDK, Pulumi |
| Containers | Docker, Kubernetes, Helm |
| GitOps | ArgoCD, Flux, Kustomize |
| Monitoring | Prometheus, Grafana, ELK/EFK |
Architecture Patterns
CI/CD Pipeline Flow
Code Commit → Build → Test → Security Scan → Package
↓
Monitor ← Release Staging ← Smoke Tests ← Deploy Dev
↓
Manual Approval
↓
Deploy ProductionGitOps Architecture
App Repo ──CI──▶ Config Repo ──ArgoCD──▶ K8s Cluster
▲ │
└────Continuous Sync─────┘Reference Files
Full working examples are in ./references/:
| File | Description | Lines |
|---|---|---|
github-actions-patterns.yaml | Complete CI/CD pipeline | 217 |
terraform-eks-module.tf | Production EKS cluster | 282 |
kubernetes-deployment.yaml | Deployment + HPA + ArgoCD | 200 |
dockerfile-multistage.dockerfile | Optimized multi-stage build | 51 |
Anti-Patterns (AVOID These)
1. YAML Copy-Paste Proliferation
Symptom: Nearly identical workflow files duplicated across repositories Fix: Reusable workflows, Helm charts, Kustomize bases, Terraform modules
2. Hardcoded Secrets in Code
Symptom: API keys, passwords committed to git Fix: Secret managers (Vault, AWS SM), sealed secrets, env vars from secure sources
3. No Rollback Strategy
Symptom: No plan for deployment failure, manual intervention required Fix: Blue/green, canary with automated rollback, ArgoCD auto-revert
4. Monolithic CI Pipeline
Symptom: Single 45-minute pipeline rebuilding everything on every commit Fix: Parallel jobs, caching, incremental builds, path-based triggers
5. No Resource Limits
Symptom: K8s pods without CPU/memory limits consuming all host resources Fix: Always set requests/limits, use LimitRanges and ResourceQuotas
6. Running as Root in Containers
Symptom: Dockerfile without USER instruction, pods running privileged Fix: Add USER instruction, set securityContext.runAsNonRoot: true
7. Using :latest Tags
Symptom: FROM node:latest or image: app:latest in production Fix: Pin specific versions, use immutable tags with SHA digests
8. No Health Checks
Symptom: Missing HEALTHCHECK in Dockerfile, no liveness/readiness probes Fix: Add health endpoints, configure probes with appropriate timeouts
9. Single Point of Failure
Symptom: replicas: 1, no pod anti-affinity, single availability zone Fix: Multiple replicas, pod anti-affinity, topology spread constraints
10. Terraform State in Local File
Symptom: terraform.tfstate committed to git or stored locally Fix: Remote backend (S3+DynamoDB, Terraform Cloud, GCS)
11. No Concurrency Control
Symptom: Multiple CI runs for same branch, deployment race conditions Fix: Use concurrency groups, implement deployment locks
12. Ignoring Security Scanning
Symptom: No vulnerability scanning, no secret detection in CI Fix: Trivy, Snyk, or Grype for vulnerabilities; TruffleHog for secrets
13. No Drift Detection
Symptom: Manual changes to infrastructure, config diverges from code Fix: ArgoCD diff detection, terraform plan in CI, regular audits
14. Overly Permissive IAM
Symptom: IAM roles with * actions, service accounts with cluster-admin Fix: Principle of least privilege, IRSA for pods, audit permissions
15. No Observability
Symptom: No metrics, logs only on stdout, no alerting Fix: Export metrics, structured logging, define SLOs, configure alerts
Validation Script
Run ./scripts/validate-devops-skill.sh to check:
- GitHub Actions workflows for deprecated actions, missing caching
- Dockerfiles for security best practices
- Kubernetes manifests for resource limits, security contexts
- Terraform for version constraints, sensitive defaults
Quality Checklist
[ ] All secrets in secret management (not in code)
[ ] Resource limits defined for all containers
[ ] Health checks configured (liveness, readiness)
[ ] Horizontal pod autoscaling enabled
[ ] Security contexts set (non-root, read-only)
[ ] Monitoring and alerting configured
[ ] Rollback strategy documented
[ ] Multi-environment support (dev, staging, prod)
[ ] Concurrency controls in CI pipelines
[ ] Remote state backend for Terraform
[ ] Vulnerability scanning in pipeline
[ ] Version pinning for all dependenciesOutput Artifacts
1. CI/CD Workflows - GitHub Actions, GitLab CI configs 2. Terraform Modules - Reusable infrastructure components 3. Kubernetes Manifests - Deployments, services, configs 4. Helm Charts - Packaged applications 5. Docker Configurations - Optimized multi-stage builds 6. ArgoCD Applications - GitOps deployment definitions
Tools Available
Read,Write,Edit- File operations for configs and manifestsBash(docker:*)- Build and manage containersBash(kubectl:*)- Kubernetes operationsBash(terraform:*)- Infrastructure provisioningBash(helm:*)- Helm chart managementBash(gh:*)- GitHub CLI operations
Changelog
All notable changes to the devops-automator skill will be documented in this file.
[2.0.0] - 2024-12-11
Changed
- BREAKING: Restructured SKILL.md from 955 lines to 171 lines for progressive disclosure
- Moved all large code examples to
./references/directory - Expanded anti-patterns section from 5 to 15 patterns
Added
references/github-actions-patterns.yaml- Complete CI/CD pipeline with lint, test, security, build, deploy stagesreferences/terraform-eks-module.tf- Production-ready EKS cluster with OIDC, node groups, encryptionreferences/kubernetes-deployment.yaml- Deployment, Service, HPA, ArgoCD Application definitionsreferences/dockerfile-multistage.dockerfile- Optimized 3-stage Docker build with security best practicesscripts/validate-devops-skill.sh- Validation script for GitHub Actions, Dockerfile, K8s, Terraform- New anti-patterns: Running as Root, Using :latest Tags, No Health Checks, Single Point of Failure, Terraform State Local, No Concurrency Control, Ignoring Security Scanning, No Drift Detection, Overly Permissive IAM, No Observability
- Expanded quality checklist with 12 items
- Version number in frontmatter
Removed
- Inline code examples (now in references/)
- Redundant capability descriptions
[1.0.0] - 2024-12-10
Added
- Initial release
- CI/CD pipeline design capabilities
- Infrastructure as code patterns
- Container orchestration support
- GitOps workflow patterns
- Monitoring and observability guidance
# Multi-Stage Dockerfile Reference
# Optimized production build pattern
# Stage 1: Dependencies
FROM node:20-alpine AS deps
WORKDIR /app
# Install dependencies based on lockfile
COPY package.json package-lock.json ./
RUN npm ci --only=production && npm cache clean --force
# Stage 2: Builder
FROM node:20-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
# Build application
RUN npm run build
# Stage 3: Production
FROM node:20-alpine AS runner
WORKDIR /app
# Security: Run as non-root user
RUN addgroup --system --gid 1001 nodejs && \
adduser --system --uid 1001 appuser
# Copy only necessary files
COPY --from=deps /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package.json ./
# Set ownership
RUN chown -R appuser:nodejs /app
USER appuser
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1
# Runtime configuration
ENV NODE_ENV=production
ENV PORT=3000
EXPOSE 3000
CMD ["node", "dist/server.js"]
# GitHub Actions Patterns Reference
# Extracted from devops-automator skill for progressive disclosure
# Complete CI/CD Pipeline Example
name: CI/CD Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run linters
run: |
npm run lint
npm run typecheck
test:
runs-on: ubuntu-latest
needs: lint
services:
postgres:
image: postgres:15
env:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: test
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run unit tests
run: npm run test:unit -- --coverage
- name: Run integration tests
run: npm run test:integration
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test
- name: Upload coverage
uses: codecov/codecov-action@v4
with:
files: ./coverage/lcov.info
fail_ci_if_error: true
security-scan:
runs-on: ubuntu-latest
needs: lint
steps:
- uses: actions/checkout@v4
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
ignore-unfixed: true
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
- name: Upload Trivy scan results
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: 'trivy-results.sarif'
- name: Run secret scanning
uses: trufflesecurity/trufflehog@main
with:
extra_args: --only-verified
build:
runs-on: ubuntu-latest
needs: [test, security-scan]
permissions:
contents: read
packages: write
outputs:
image-tag: ${{ steps.meta.outputs.tags }}
image-digest: ${{ steps.build-push.outputs.digest }}
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=sha,prefix=
type=semver,pattern={{version}}
- name: Build and push
id: build-push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
platforms: linux/amd64,linux/arm64
deploy-staging:
runs-on: ubuntu-latest
needs: build
if: github.ref == 'refs/heads/main'
environment:
name: staging
url: https://staging.example.com
steps:
- uses: actions/checkout@v4
- name: Set up kubectl
uses: azure/setup-kubectl@v3
- name: Configure kubectl
run: |
echo "${{ secrets.KUBE_CONFIG_STAGING }}" | base64 -d > kubeconfig
export KUBECONFIG=$(pwd)/kubeconfig
- name: Deploy to staging
run: |
kubectl set image deployment/app \
app=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ needs.build.outputs.image-digest }} \
-n staging
- name: Wait for rollout
run: |
kubectl rollout status deployment/app -n staging --timeout=300s
- name: Run smoke tests
run: |
curl -f https://staging.example.com/health || exit 1
deploy-production:
runs-on: ubuntu-latest
needs: [build, deploy-staging]
if: github.ref == 'refs/heads/main'
environment:
name: production
url: https://example.com
steps:
- uses: actions/checkout@v4
- name: Deploy to production
uses: actions/github-script@v7
with:
script: |
// Blue/green deployment logic
console.log('Deploying to production...')
- name: Notify on success
uses: slackapi/slack-github-action@v1
with:
channel-id: 'deployments'
payload: |
{
"text": "✅ Deployed to production: ${{ github.sha }}"
}
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
# Kubernetes Deployment Reference
# Production-ready patterns for devops-automator skill
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
labels:
app.kubernetes.io/name: app
app.kubernetes.io/component: server
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app.kubernetes.io/name: app
template:
metadata:
labels:
app.kubernetes.io/name: app
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "3000"
prometheus.io/path: "/metrics"
spec:
serviceAccountName: app
securityContext:
runAsNonRoot: true
runAsUser: 1001
fsGroup: 1001
containers:
- name: app
image: app:latest
imagePullPolicy: Always
ports:
- name: http
containerPort: 3000
protocol: TCP
env:
- name: NODE_ENV
value: "production"
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: app-secrets
key: database-url
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
livenessProbe:
httpGet:
path: /health/live
port: http
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /health/ready
port: http
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir: {}
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app.kubernetes.io/name: app
topologyKey: kubernetes.io/hostname
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app.kubernetes.io/name: app
---
apiVersion: v1
kind: Service
metadata:
name: app
spec:
type: ClusterIP
ports:
- port: 80
targetPort: http
protocol: TCP
name: http
selector:
app.kubernetes.io/name: app
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: app
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: app
minReplicas: 3
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 10
periodSeconds: 60
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100
periodSeconds: 15
- type: Pods
value: 4
periodSeconds: 15
selectPolicy: Max
---
# ArgoCD Application Definition
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: app
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
source:
repoURL: https://github.com/org/config-repo
targetRevision: HEAD
path: k8s/overlays/production
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true
selfHeal: true
allowEmpty: false
syncOptions:
- CreateNamespace=true
- PrunePropagationPolicy=foreground
- PruneLast=true
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m
ignoreDifferences:
- group: apps
kind: Deployment
jsonPointers:
- /spec/replicas
# Terraform EKS Cluster Module
# Reference implementation for devops-automator skill
terraform {
required_version = ">= 1.5"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
kubernetes = {
source = "hashicorp/kubernetes"
version = "~> 2.23"
}
}
}
# Variables
variable "cluster_name" {
description = "Name of the EKS cluster"
type = string
}
variable "cluster_version" {
description = "Kubernetes version"
type = string
default = "1.28"
}
variable "vpc_id" {
description = "VPC ID for the cluster"
type = string
}
variable "subnet_ids" {
description = "Subnet IDs for the cluster"
type = list(string)
}
variable "node_groups" {
description = "Node group configurations"
type = map(object({
instance_types = list(string)
capacity_type = string
min_size = number
max_size = number
desired_size = number
labels = map(string)
taints = list(object({
key = string
value = string
effect = string
}))
}))
default = {}
}
variable "enable_cluster_autoscaler" {
description = "Enable cluster autoscaler"
type = bool
default = true
}
variable "tags" {
description = "Tags to apply to resources"
type = map(string)
default = {}
}
# Data sources
data "aws_caller_identity" "current" {}
data "aws_region" "current" {}
# IAM Role for EKS Cluster
resource "aws_iam_role" "cluster" {
name = "${var.cluster_name}-cluster-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "eks.amazonaws.com"
}
}]
})
tags = var.tags
}
resource "aws_iam_role_policy_attachment" "cluster_AmazonEKSClusterPolicy" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy"
role = aws_iam_role.cluster.name
}
# EKS Cluster
resource "aws_eks_cluster" "main" {
name = var.cluster_name
version = var.cluster_version
role_arn = aws_iam_role.cluster.arn
vpc_config {
subnet_ids = var.subnet_ids
endpoint_private_access = true
endpoint_public_access = true
security_group_ids = [aws_security_group.cluster.id]
}
enabled_cluster_log_types = [
"api",
"audit",
"authenticator",
"controllerManager",
"scheduler"
]
encryption_config {
provider {
key_arn = aws_kms_key.eks.arn
}
resources = ["secrets"]
}
depends_on = [
aws_iam_role_policy_attachment.cluster_AmazonEKSClusterPolicy,
]
tags = var.tags
}
# KMS Key for secrets encryption
resource "aws_kms_key" "eks" {
description = "EKS Secret Encryption Key"
deletion_window_in_days = 7
enable_key_rotation = true
tags = var.tags
}
# Security Group for Cluster
resource "aws_security_group" "cluster" {
name = "${var.cluster_name}-cluster-sg"
description = "Security group for EKS cluster"
vpc_id = var.vpc_id
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = merge(var.tags, {
Name = "${var.cluster_name}-cluster-sg"
})
}
# IAM Role for Node Groups
resource "aws_iam_role" "node" {
name = "${var.cluster_name}-node-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "ec2.amazonaws.com"
}
}]
})
tags = var.tags
}
resource "aws_iam_role_policy_attachment" "node_AmazonEKSWorkerNodePolicy" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy"
role = aws_iam_role.node.name
}
resource "aws_iam_role_policy_attachment" "node_AmazonEKS_CNI_Policy" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy"
role = aws_iam_role.node.name
}
resource "aws_iam_role_policy_attachment" "node_AmazonEC2ContainerRegistryReadOnly" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
role = aws_iam_role.node.name
}
# Node Groups
resource "aws_eks_node_group" "main" {
for_each = var.node_groups
cluster_name = aws_eks_cluster.main.name
node_group_name = each.key
node_role_arn = aws_iam_role.node.arn
subnet_ids = var.subnet_ids
instance_types = each.value.instance_types
capacity_type = each.value.capacity_type
scaling_config {
min_size = each.value.min_size
max_size = each.value.max_size
desired_size = each.value.desired_size
}
update_config {
max_unavailable = 1
}
labels = each.value.labels
dynamic "taint" {
for_each = each.value.taints
content {
key = taint.value.key
value = taint.value.value
effect = taint.value.effect
}
}
depends_on = [
aws_iam_role_policy_attachment.node_AmazonEKSWorkerNodePolicy,
aws_iam_role_policy_attachment.node_AmazonEKS_CNI_Policy,
aws_iam_role_policy_attachment.node_AmazonEC2ContainerRegistryReadOnly,
]
tags = merge(var.tags, {
"k8s.io/cluster-autoscaler/${var.cluster_name}" = "owned"
"k8s.io/cluster-autoscaler/enabled" = var.enable_cluster_autoscaler ? "true" : "false"
})
lifecycle {
ignore_changes = [scaling_config[0].desired_size]
}
}
# OIDC Provider for IAM Roles for Service Accounts (IRSA)
data "tls_certificate" "eks" {
url = aws_eks_cluster.main.identity[0].oidc[0].issuer
}
resource "aws_iam_openid_connect_provider" "eks" {
client_id_list = ["sts.amazonaws.com"]
thumbprint_list = [data.tls_certificate.eks.certificates[0].sha1_fingerprint]
url = aws_eks_cluster.main.identity[0].oidc[0].issuer
tags = var.tags
}
# Outputs
output "cluster_id" {
description = "EKS cluster ID"
value = aws_eks_cluster.main.id
}
output "cluster_endpoint" {
description = "EKS cluster endpoint"
value = aws_eks_cluster.main.endpoint
}
output "cluster_certificate_authority_data" {
description = "Base64 encoded certificate data"
value = aws_eks_cluster.main.certificate_authority[0].data
}
output "cluster_oidc_issuer_url" {
description = "OIDC issuer URL"
value = aws_eks_cluster.main.identity[0].oidc[0].issuer
}
output "cluster_oidc_provider_arn" {
description = "OIDC provider ARN"
value = aws_iam_openid_connect_provider.eks.arn
}
output "node_security_group_id" {
description = "Security group ID for nodes"
value = aws_security_group.cluster.id
}
#!/bin/bash
# DevOps Automator Skill Validation Script
# Validates DevOps configurations for common issues
set -e
SKILL_DIR="$(dirname "$0")/.."
ERRORS=0
WARNINGS=0
echo "═══════════════════════════════════════════════════════════════"
echo "DevOps Automator Skill Validator"
echo "═══════════════════════════════════════════════════════════════"
echo ""
# Check for GitHub Actions workflow files
check_github_actions() {
echo "🔍 Checking GitHub Actions workflows..."
if [ -d ".github/workflows" ]; then
for workflow in .github/workflows/*.yml .github/workflows/*.yaml; do
[ -f "$workflow" ] || continue
# Check for deprecated actions
if grep -q "actions/checkout@v2\|actions/checkout@v3" "$workflow" 2>/dev/null; then
echo "⚠️ WARN: $workflow uses outdated checkout action (use v4)"
((WARNINGS++))
fi
# Check for missing concurrency controls
if ! grep -q "concurrency:" "$workflow" 2>/dev/null; then
echo "⚠️ WARN: $workflow missing concurrency control"
((WARNINGS++))
fi
# Check for hardcoded secrets
if grep -qE "(password|secret|token):\s*['\"][^{]" "$workflow" 2>/dev/null; then
echo "❌ ERROR: $workflow may contain hardcoded secrets"
((ERRORS++))
fi
# Check for caching
if ! grep -q "cache:" "$workflow" 2>/dev/null; then
echo "⚠️ WARN: $workflow missing caching (slower builds)"
((WARNINGS++))
fi
done
else
echo "ℹ️ No GitHub Actions workflows found"
fi
}
# Check Dockerfile best practices
check_dockerfile() {
echo ""
echo "🐳 Checking Dockerfiles..."
for dockerfile in Dockerfile Dockerfile.*; do
[ -f "$dockerfile" ] || continue
# Check for USER instruction (non-root)
if ! grep -q "^USER " "$dockerfile" 2>/dev/null; then
echo "⚠️ WARN: $dockerfile runs as root (add USER instruction)"
((WARNINGS++))
fi
# Check for HEALTHCHECK
if ! grep -q "^HEALTHCHECK " "$dockerfile" 2>/dev/null; then
echo "⚠️ WARN: $dockerfile missing HEALTHCHECK"
((WARNINGS++))
fi
# Check for latest tag
if grep -qE "^FROM .+:latest" "$dockerfile" 2>/dev/null; then
echo "❌ ERROR: $dockerfile uses :latest tag (pin versions)"
((ERRORS++))
fi
# Check for multi-stage build
if [ $(grep -c "^FROM " "$dockerfile" 2>/dev/null) -lt 2 ]; then
echo "ℹ️ INFO: $dockerfile is not multi-stage (consider optimization)"
fi
done
}
# Check Kubernetes manifests
check_kubernetes() {
echo ""
echo "☸️ Checking Kubernetes manifests..."
for manifest in k8s/*.yaml k8s/**/*.yaml kubernetes/*.yaml; do
[ -f "$manifest" ] || continue
# Check for resource limits
if grep -q "kind: Deployment\|kind: StatefulSet" "$manifest" 2>/dev/null; then
if ! grep -q "resources:" "$manifest" 2>/dev/null; then
echo "❌ ERROR: $manifest missing resource limits"
((ERRORS++))
fi
fi
# Check for liveness/readiness probes
if grep -q "kind: Deployment" "$manifest" 2>/dev/null; then
if ! grep -q "livenessProbe:\|readinessProbe:" "$manifest" 2>/dev/null; then
echo "⚠️ WARN: $manifest missing health probes"
((WARNINGS++))
fi
fi
# Check for security context
if ! grep -q "securityContext:" "$manifest" 2>/dev/null; then
echo "⚠️ WARN: $manifest missing security context"
((WARNINGS++))
fi
done
}
# Check Terraform configurations
check_terraform() {
echo ""
echo "🏗️ Checking Terraform configurations..."
if [ -d "terraform" ] || ls *.tf 1>/dev/null 2>&1; then
# Check for version constraints
if ! grep -q "required_version" *.tf terraform/*.tf 2>/dev/null; then
echo "⚠️ WARN: Missing Terraform version constraint"
((WARNINGS++))
fi
# Check for provider version pinning
if ! grep -q "version.*=.*\"~>" *.tf terraform/*.tf 2>/dev/null; then
echo "⚠️ WARN: Missing provider version pinning"
((WARNINGS++))
fi
# Check for sensitive variables
if grep -qE "variable.*default.*=.*(password|secret|key)" *.tf terraform/*.tf 2>/dev/null; then
echo "❌ ERROR: Sensitive defaults in Terraform variables"
((ERRORS++))
fi
else
echo "ℹ️ No Terraform configurations found"
fi
}
# Run all checks
check_github_actions
check_dockerfile
check_kubernetes
check_terraform
# Summary
echo ""
echo "═══════════════════════════════════════════════════════════════"
echo "Validation Complete"
echo "═══════════════════════════════════════════════════════════════"
echo "Errors: $ERRORS"
echo "Warnings: $WARNINGS"
echo ""
if [ $ERRORS -gt 0 ]; then
echo "❌ Validation FAILED - fix errors before deployment"
exit 1
elif [ $WARNINGS -gt 5 ]; then
echo "⚠️ Validation PASSED with warnings - review recommended"
exit 0
else
echo "✅ Validation PASSED"
exit 0
fi