Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Sets up GitHub Actions CI/CD workflow for automatic deployment to AWS on push to main. Uses GitHub OIDC for keyless AWS authentication.
.claude/skills/grcengclub-website-cicd/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-13 | ✗→✓ | ▲ Improved | 58% | 0% |
| case-14 | ✗→✓ | ▲ Improved | 61% | 0% |
| case-16 | ✗→✓ | ▲ Improved | 27% | 0% |
| case-17 | ✗→✓ | ▲ Improved | 215% | 0% |
| case-18 | ✗→✓ | ▲ Improved | 49% | 0% |
You are running the /grc-portfolio:cicd skill. Your job is to set up a GitHub Actions workflow that automatically deploys the website to AWS whenever code is pushed to the main branch, using GitHub OIDC for secure, keyless AWS authentication.
Find site-config.json:
$ARGUMENTS for a project directory pathRead it and validate:
status.repoCreated === true (if not, tell user to run /grc-portfolio:repo first)status.infraDeployed === true (if not, tell user to run /grc-portfolio:infra first)Check if the GitHub OIDC identity provider already exists in the AWS account:
bashaws iam list-open-id-connect-providers --profile <aws.profile>
Look for token.actions.githubusercontent.com. If it doesn't exist, create it:
bashaws iam create-open-id-connect-provider \ --url https://token.actions.githubusercontent.com \ --client-id-list sts.amazonaws.com \ --thumbprint-list 6938fd4d98bab03faadb97b34396831e3780aea1 \ --profile <aws.profile>
Create a trust policy that allows only this specific GitHub repo's main branch (and workflow_dispatch runs against main) to assume the role. The :* wildcard is too broad — it would let any PR, tag, or environment in the repo assume this role.
json{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::<account-id>:oidc-provider/token.actions.githubusercontent.com" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "token.actions.githubusercontent.com:aud": "sts.amazonaws.com", "token.actions.githubusercontent.com:sub": "repo:<github.owner>/<github.repoName>:ref:refs/heads/main" } } } ] }
If the project deploys from a different branch, replace main accordingly. For preview deploys from PRs, add a second statement scoped to repo:<owner>/<repo>:pull_request and a separate, narrower IAM policy.
Create the role:
bashaws iam create-role \ --role-name <projectName>-github-deploy \ --assume-role-policy-document file:///tmp/<projectName>-trust-policy.json \ --description "GitHub Actions OIDC role for <projectName> website deployment" \ --profile <aws.profile>
Create an inline policy scoped to only the S3 bucket and CloudFront distribution for this project:
json{ "Version": "2012-10-17", "Statement": [ { "Sid": "S3Deploy", "Effect": "Allow", "Action": [ "s3:PutObject", "s3:GetObject", "s3:DeleteObject", "s3:ListBucket" ], "Resource": [ "arn:aws:s3:::<aws.bucketName>", "arn:aws:s3:::<aws.bucketName>/*" ] }, { "Sid": "CloudFrontInvalidate", "Effect": "Allow", "Action": "cloudfront:CreateInvalidation", "Resource": "arn:aws:cloudfront::<account-id>:distribution/<aws.distributionId>" } ] }
Attach it:
bashaws iam put-role-policy \ --role-name <projectName>-github-deploy \ --policy-name <projectName>-deploy-access \ --policy-document file:///tmp/<projectName>-deploy-policy.json \ --profile <aws.profile>
Create .github/workflows/deploy.yml in the project directory.
The workflow uses OIDC — no static AWS keys needed. Bucket name, distribution ID, and role ARN are stored as workflow env vars (not secrets, since they're not sensitive):
yamlname: Deploy to AWS on: push: branches: - main workflow_dispatch: permissions: id-token: write contents: read env: AWS_BUCKET_NAME: <aws.bucketName> AWS_DISTRIBUTION_ID: <aws.distributionId> AWS_REGION: us-east-1 AWS_ROLE_ARN: arn:aws:iam::<account-id>:role/<projectName>-github-deploy jobs: deploy: name: Build and Deploy runs-on: ubuntu-latest steps: - name: Checkout code 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: Build project run: npm run build env: NODE_ENV: production - name: Configure AWS credentials (OIDC) uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: ${{ env.AWS_ROLE_ARN }} aws-region: ${{ env.AWS_REGION }} - name: Deploy to S3 run: | aws s3 sync dist/ s3://${{ env.AWS_BUCKET_NAME }} \ --delete \ --cache-control "public,max-age=31536000,immutable" \ --exclude "index.html" \ --exclude "*.html" aws s3 sync dist/ s3://${{ env.AWS_BUCKET_NAME }} \ --cache-control "public,max-age=0,must-revalidate" \ --exclude "*" \ --include "*.html" - name: Invalidate CloudFront run: | aws cloudfront create-invalidation \ --distribution-id ${{ env.AWS_DISTRIBUTION_ID }} \ --paths "/*"
If features.contactForm is true, add to the Build step's env:
yamlenv: NODE_ENV: production VITE_CONTACT_API_ENDPOINT: <aws.contactApiEndpoint>
bashcd <projectDir> git add .github/workflows/deploy.yml git commit -m "Add GitHub Actions deploy workflow (OIDC auth)" git push
Check that the workflow was triggered:
bashgh run list --limit 1
If the run is in progress, tell the user. If it completed, report the status:
bashgh run view <run-id>
Update site-config.json:
github.secretsConfigured = truestatus.cicdConfigured = trueTell the user:
<projectName>-github-deploy is scoped to only S3 + CloudFront for this projectmain will automatically build and deploy the site<github.repoUrl>/actions$TOOLKIT_DIR = read from site-config.json toolkitDir field$ARGUMENTS = arguments passed after /cicd (expected: project directory path)| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 9,547 | 6,066 | -36% | 1 | 1 | 0% | 1,884 | 2,125 | +13% | 0 | 0 | — |
case-02 | fail→fail | 12,137 | 3,919 | -68% | 1 | 1 | 0% | 2,250 | 2,153 | -4% | 0 | 0 | — |
case-03 | fail→fail | 16,022 | 2,667 | -83% | 1 | 1 | 0% | 2,770 | 2,094 | -24% | 0 | 0 | — |
case-04 | pass→fail | 9,251 | 5,924 | -36% | 1 | 1 | 0% | 1,565 | 2,309 | +48% | 0 | 0 | — |
case-05 | pass→fail | 14,854 | 5,074 | -66% | 1 | 1 | 0% | 2,759 | 2,216 | -20% | 0 | 0 | — |
case-06 | pass→fail | 12,431 | 5,325 | -57% | 1 | 1 | 0% | 2,196 | 2,163 | -2% | 0 | 0 | — |
case-07 | pass→pass | 13,136 | 4,283 | -67% | 1 | 1 | 0% | 1,782 | 2,703 | +52% | 0 | 0 | — |
case-08 | pass→pass | 9,121 | 5,387 | -41% | 1 | 1 | 0% | 1,656 | 2,938 | +77% | 0 | 0 | — |
case-09 | pass→pass | 13,207 | 5,645 | -57% | 1 | 1 | 0% | 2,286 | 2,971 | +30% | 0 | 0 | — |
case-10 | pass→pass | 6,724 | 3,192 | -53% | 1 | 1 | 0% | 1,221 | 2,537 | +108% | 0 | 0 | — |
case-11 | pass→pass | 5,717 | 3,388 | -41% | 1 | 1 | 0% | 928 | 2,461 | +165% | 0 | 0 | — |
case-12 | pass→pass | 8,202 | 3,499 | -57% | 1 | 1 | 0% | 1,373 | 2,452 | +79% | 0 | 0 | — |
case-13 | fail→pass | 10,787 | 5,790 | -46% | 1 | 1 | 0% | 1,855 | 2,931 | +58% | 0 | 0 | — |
case-14 | fail→pass | 11,906 | 7,017 | -41% | 1 | 1 | 0% | 1,957 | 3,143 | +61% | 0 | 0 | — |
case-15 | pass→pass | 8,174 | 4,117 | -50% | 1 | 1 | 0% | 1,396 | 2,722 | +95% | 0 | 0 | — |
case-16 | fail→pass | 9,325 | 1,745 | -81% | 1 | 1 | 0% | 1,761 | 2,244 | +27% | 0 | 0 | — |
case-17 | fail→pass | 4,869 | 1,540 | -68% | 1 | 1 | 0% | 679 | 2,141 | +215% | 0 | 0 | — |
case-18 | fail→pass | 10,908 | 3,825 | -65% | 1 | 1 | 0% | 1,688 | 2,522 | +49% | 0 | 0 | — |
case-19 | fail→pass | 10,879 | 1,961 | -82% | 1 | 1 | 0% | 1,736 | 2,221 | +28% | 0 | 0 | — |
case-20 | fail→pass | 11,164 | 2,611 | -77% | 1 | 1 | 0% | 1,746 | 2,323 | +33% | 0 | 0 | — |
case-21 | fail→pass | 10,312 | 1,980 | -81% | 1 | 1 | 0% | 1,525 | 2,252 | +48% | 0 | 0 | — |
case-22 | fail→pass | 11,989 | 2,086 | -83% | 1 | 1 | 0% | 1,848 | 2,304 | +25% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 16 counted toward the lift figure. The other 6 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +27 percentage points is the difference between those two pass rates over the 16 comparable cases. 4 cases got worse with the skill loaded, and they are included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.