What you get is AI-generated correction suggestions for perceived harmful Cloud infra. You decide whether or not to action the suggestions.
Close cloud findings the way you ship code: one pull request per finding, a live-state check before anything mutates, applied on merge. The whole loop runs in GitHub Actions, authenticates with OIDC (no long-lived keys), and uses StackQL to read and act on cloud control planes. The bundled checks are FinOps waste (unattached disks, idle IPs, zero-VM projects); the shape works the same for security posture and access.
- A scheduled or dispatched audit queries the control plane and writes findings as JSON.
- For each finding, the loop opens one PR carrying the exact proposed SQL.
- A preflight status check re-queries live state; the PR cannot merge unless it passes.
- On merge, the change is applied via StackQL using mutate OIDC identities.
- A post-apply check confirms the resource is gone.
There is no LLM in the SQL path — the fix comes from the audit's own suggested_remediation block. A model is used only in one optional step to flag captain's-call risks for reviewers.
.github/workflows/
ai-agent-remediation-oidc-audit-workflow.yml # audit -> proposals -> PRs
pr-preflight.yml # required preflight check on each PR
pr-merge-apply.yml # apply on merge + post-check (OIDC mutate)
cicd/onboarding/ # per-cloud bootstrap + teardown
remediations/proposed/<run-id>/<finding>/ # generated proposals (one dir per finding)
Settings → Branches → add rule for main:
- Require status checks to pass → add
preflight - Required approvals → 0
The preflight check (not a human) gates merge. Or via CLI — name your repo explicitly (on a fork, gh has no default repo and bare commands silently target the wrong one):
REPO=<owner>/<repo>
gh api -X PUT "repos/$REPO/branches/main/protection" \
-f 'required_status_checks[strict]=true' -f 'required_status_checks[contexts][]=preflight' \
-F 'enforce_admins=false' -F 'required_pull_request_reviews[required_approving_review_count]=0' -F 'restrictions=null'PRs show "1 workflow awaiting approval" because the bot authors them — click Approve workflows to run on each PR.
📖 Full OIDC principal lifecycle — stand up and tear down — is documented end-to-end in
cicd/onboarding/onboarding.md. A paste-run bootstrap script per cloud, and a dry-run-first, idempotent teardown that shows exactly what it removes before it runs. In an enterprise, hand your IAM team the exact roles from that guide.
Bootstrap runs inside your own cloud console session; only an identifier comes back to the pipeline.
- AWS: deploy
cicd/onboarding/aws/template.yaml(CloudFormation) → role ARN. - GCP: run
cicd/onboarding/gcp/setup.sh(Cloud Shell) → WIF provider + service account. - Azure: deploy
cicd/onboarding/azure/template.json(ARM) → federated credential.
Each script prints the exact identifiers to paste in the next step. Wire up only the clouds you use; the workflows skip any provider whose secrets are missing.
Store everything as repository Secrets (Settings → Secrets and variables → Actions → Secrets). Set only the clouds you use — each provider runs only when every secret in its row is present, otherwise it is skipped with a message naming the missing secret.
Required for every run: ANTHROPIC_API_KEY (proposal + PR generation). Without it the audit runs but no PRs open.
| Provider | Audit + preflight (read) | Apply on merge (write) |
|---|---|---|
| AWS | STACKQL_ID_FED_AWS_ROLE_ARN |
STACKQL_ID_FED_AWS_MUTATE_ROLE_ARN |
| GCP | STACKQL_ID_FED_GCP_WORKLOAD_IDENTITY_PROVIDER, STACKQL_ID_FED_GCP_SERVICE_ACCOUNT, GCP_ORG_ID |
STACKQL_ID_FED_GCP_WORKLOAD_IDENTITY_PROVIDER, STACKQL_ID_FED_GCP_MUTATE_SERVICE_ACCOUNT |
| Azure | STACKQL_ID_FED_AZURE_TENANT_ID, STACKQL_ID_FED_AZURE_CLIENT_ID, AZURE_SUB_ID |
STACKQL_ID_FED_AZURE_TENANT_ID, STACKQL_ID_FED_AZURE_MUTATE_CLIENT_ID, AZURE_SUB_ID |
GCP_ORG_ID (org ID, digits only) scopes the GCP audit's org→project descent — without it the GCP leg finds nothing.
Trigger the audit — Actions → AI Agent Action post Cloud FinOps Audit (OIDC) → Run workflow, or push a tag:
git tag ai-remediate-finops-oidc-1 && git push origin ai-remediate-finops-oidc-1Findings upload as artifacts, proposals generate, and one PR opens per finding. Merge a green PR; the apply and post-check run on the merge.
Return to a clean state between runs. Defaults to dry-run so you can inspect first.
# Preview (no changes)
DRY_RUN=true CLOUDS="aws gcp azure" PROJECT_ID=<gcp-project-id> REPO=<owner>/<repo> bash cicd/onboarding/reset.sh
# Execute — add CLEAN_GITHUB=true GH_REPO=<owner>/<repo> to also remove the repo secrets
DRY_RUN=false CLOUDS="aws gcp azure" PROJECT_ID=<gcp-project-id> REPO=<owner>/<repo> bash cicd/onboarding/reset.shPer-cloud scripts: aws/teardown.sh, gcp/teardown.sh, azure/teardown.sh.
Clear accumulated remediation branches:
git push origin --delete $(git ls-remote --heads origin 'remediation*' | sed -E 's#^.*refs/heads/##')Questions or help getting set up: actions@stackql.io
Powered by StackQL.