{"id":51457503,"url":"https://github.com/malpanez/ansible-devcontainer-vscode","last_synced_at":"2026-07-06T02:00:39.434Z","repository":{"id":321583626,"uuid":"1085991888","full_name":"malpanez/ansible-devcontainer-vscode","owner":"malpanez","description":"Modern, reproducible infrastructure development environments powered by VS Code Dev Containers and the `uv` Python toolchain. Open the repository in VS Code, pick the stack you need (Ansible, Terraform, Golang, or LaTeX), reopen in a container, and you are ready to lint, test, and ship automation from any platform (Windows + WSL2, macOS, or Linux).","archived":false,"fork":false,"pushed_at":"2026-07-04T15:42:18.000Z","size":1143,"stargazers_count":3,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-04T17:06:59.852Z","etag":null,"topics":["ansible","devcontainer","devops","docker","golang","infrastructure-as-code","python","terraform","uv","vscode"],"latest_commit_sha":null,"homepage":null,"language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/malpanez.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":".github/security-alert-exceptions.yml","support":"SUPPORT.md","governance":null,"roadmap":"docs/ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["malpanez"]}},"created_at":"2025-10-29T19:44:40.000Z","updated_at":"2026-07-04T12:48:38.000Z","dependencies_parsed_at":"2025-10-30T13:24:56.774Z","dependency_job_id":"7cb2f719-5a58-4624-8b75-c0bd1174bd46","html_url":"https://github.com/malpanez/ansible-devcontainer-vscode","commit_stats":null,"previous_names":["malpanez/ansible-devcontainer-vscode"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/malpanez/ansible-devcontainer-vscode","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/malpanez%2Fansible-devcontainer-vscode","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/malpanez%2Fansible-devcontainer-vscode/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/malpanez%2Fansible-devcontainer-vscode/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/malpanez%2Fansible-devcontainer-vscode/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/malpanez","download_url":"https://codeload.github.com/malpanez/ansible-devcontainer-vscode/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/malpanez%2Fansible-devcontainer-vscode/sbom","scorecard":{"id":1240206,"data":{"date":"2025-12-05T07:44:55Z","repo":{"name":"github.com/malpanez/ansible-devcontainer-vscode","commit":"943d7ae099f4ba36469dbb7f0a4d17ccd6507366"},"scorecard":{"version":"v5.3.0","commit":"c22063e786c11f9dd714d777a687ff7c4599b600"},"score":4.9,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#packaging"}},{"name":"Code-Review","score":0,"reason":"Found 1/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"project was created within the last 90 days. Please review its contents carefully","details":["Warn: Repository was created within the last 90 days."],"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#maintained"}},{"name":"Security-Policy","score":10,"reason":"security policy file detected","details":["Info: security policy file detected: SECURITY.md:1","Info: Found linked content: SECURITY.md:1","Info: Found disclosure, vulnerability, and/or timelines in security policy: SECURITY.md:1","Info: Found text in security policy: SECURITY.md:1"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#security-policy"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#binary-artifacts"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#dangerous-workflow"}},{"name":"Pinned-Dependencies","score":5,"reason":"dependency not pinned by hash detected -- score normalized to 5","details":["Warn: downloadThenRun not pinned by hash: devcontainers/ansible/Dockerfile:62","Warn: downloadThenRun not pinned by hash: devcontainers/ansible/Dockerfile.podman:82","Warn: pipCommand not pinned by hash: devcontainers/base/Dockerfile:71","Warn: downloadThenRun not pinned by hash: devcontainers/golang/Dockerfile:30","Warn: downloadThenRun not pinned by hash: devcontainers/latex/Dockerfile:59","Warn: downloadThenRun not pinned by hash: devcontainers/terraform/Dockerfile:95","Info:   8 out of   8 containerImage dependencies pinned","Info:   0 out of   5 downloadThenRun dependencies pinned","Info:   0 out of   1 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#cii-best-practices"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":10,"reason":"SAST tool is run on all commits","details":["Info: all commits (26) are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#sast"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#signed-releases"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#fuzzing"}},{"name":"Dependency-Update-Tool","score":0,"reason":"no update tool detected","details":["Warn: no dependency update tool configurations found"],"documentation":{"short":"Determines if the project uses a dependency update tool.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#dependency-update-tool"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#branch-protection"}},{"name":"Contributors","score":3,"reason":"project has 1 contributing companies or organizations -- score normalized to 3","details":["Info: found contributions from: winning concepts limited"],"documentation":{"short":"Determines if the project has a set of contributors from multiple organizations (e.g., companies).","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#contributors"}},{"name":"CI-Tests","score":10,"reason":"26 out of 26 merged PRs checked by a CI test -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project runs tests before pull requests are merged.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#ci-tests"}}]},"last_synced_at":"2025-12-05T11:48:59.475Z","repository_id":321583626,"created_at":"2025-12-05T11:48:59.475Z","updated_at":"2025-12-05T11:48:59.475Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35175119,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-06T02:00:07.184Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ansible","devcontainer","devops","docker","golang","infrastructure-as-code","python","terraform","uv","vscode"],"created_at":"2026-07-06T02:00:24.617Z","updated_at":"2026-07-06T02:00:39.419Z","avatar_url":"https://github.com/malpanez.png","language":"Shell","funding_links":["https://github.com/sponsors/malpanez"],"categories":[],"sub_categories":[],"readme":"# Infrastructure Dev Containers for VS Code\n\n[![CI Pipeline](https://github.com/malpanez/ansible-devcontainer-vscode/actions/workflows/ci.yml/badge.svg)](https://github.com/malpanez/ansible-devcontainer-vscode/actions/workflows/ci.yml)\n[![Build Containers](https://github.com/malpanez/ansible-devcontainer-vscode/actions/workflows/build-containers.yml/badge.svg)](https://github.com/malpanez/ansible-devcontainer-vscode/actions/workflows/build-containers.yml)\n[![CodeQL](https://github.com/malpanez/ansible-devcontainer-vscode/actions/workflows/codeql.yml/badge.svg)](https://github.com/malpanez/ansible-devcontainer-vscode/actions/workflows/codeql.yml)\n[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/malpanez/ansible-devcontainer-vscode/badge)](https://securityscorecards.dev/viewer/?uri=github.com/malpanez/ansible-devcontainer-vscode)\n[![SBOM](https://github.com/malpanez/ansible-devcontainer-vscode/actions/workflows/sbom-verification.yml/badge.svg)](https://github.com/malpanez/ansible-devcontainer-vscode/actions/workflows/sbom-verification.yml)\n[![Code Quality](https://github.com/malpanez/ansible-devcontainer-vscode/actions/workflows/quality.yml/badge.svg)](https://github.com/malpanez/ansible-devcontainer-vscode/actions/workflows/quality.yml)\n[![License: MIT](https://img.shields.io/badge/license-MIT-yellow)](LICENSE)\n\n[![GHCR](https://img.shields.io/badge/GHCR-images-blue?logo=github)](https://github.com/malpanez?tab=packages\u0026repo_name=ansible-devcontainer-vscode)\n[![Open in GitHub Codespaces](https://img.shields.io/badge/Codespaces-Open-blue?logo=github)](https://codespaces.new/malpanez/ansible-devcontainer-vscode)\n[![Renovate](https://img.shields.io/badge/renovate-enabled-brightgreen?logo=renovatebot)](https://github.com/malpanez/ansible-devcontainer-vscode/issues)\n[![uv](https://img.shields.io/badge/uv-ready-00A3FF?logo=astral)](https://github.com/astral-sh/uv)\n\n**Stacks:**\n[![Ansible](https://img.shields.io/badge/ansible-9.14.0-EE0000?logo=ansible)](https://www.ansible.com/)\n[![Terraform](https://img.shields.io/badge/terraform-1.14.0-7B42BC?logo=terraform)](https://www.terraform.io/)\n[![Go](https://img.shields.io/badge/go-1.25-00ADD8?logo=go\u0026logoColor=white)](https://go.dev/)\n[![Python](https://img.shields.io/badge/python-3.12.12-3776AB?logo=python\u0026logoColor=white)](https://www.python.org/)\n\nPull a pre-built infrastructure workspace from GHCR and start writing Terraform or running Ansible in **under 30 seconds** — 3–5× smaller than Microsoft's devcontainer images, with no local setup and no drift between machines. Pick the stack you need (Ansible, Terraform, Golang, or LaTeX), reopen in VS Code, and your entire toolchain is already installed, locked, and ready. Works on Windows + WSL2, macOS, and Linux.\n\n## Highlights\n\n- ⚡ **uv-first Python workflow** – dependency installs are fast and reproducible via `uv pip install --system .` using `pyproject.toml` for the Ansible stack.\n- 🐳 **Dev Container ready** – Dockerfile, features, extensions, and VS Code settings ship in the repo.\n- 🤖 **Automation via Ansible** – `playbooks/setup-workspace.yml` provisions the container with roles for base OS tweaks, Ansible tooling, Python testing tools, and editor config.\n- 🧩 **Multi-stack templates** – ship Ansible, Terraform, Golang, and LaTeX workspaces side-by-side; switch with a single helper script.\n- 🧱 **Slim stack-specific images** – each stack is based on the leanest upstream image (Chainguard or slim Debian/Python) with layered cleanup for fast pulls.\n- 📦 **GHCR-ready images** – Dockerfiles are optimised for publishing to `ghcr.io` so teams can pull prebuilt devcontainers instead of rebuilding locally.\n- 🧪 **Quality gates baked in** – pre-commit hooks, `ansible-lint`, `yamllint`, Molecule/pytest harness, and GitHub Actions CI.\n- 🪪 **Template-driven pre-commit** – `ensure-precommit` seeds the right hook config per stack and runs `uvx pre-commit` without bloating the images.\n- 🔐 **Security conscious** – runs as non-root, includes Trivy scanning in CI, and keeps secrets out of the repo.\n- 🤖 **AI agent safe by design** – run Claude Code, Copilot, or any AI agent with full permissions inside the container. Worst case: a broken workspace, back to normal with `git reset` in seconds. Your host OS, credentials, and other projects are never at risk.\n- 📣 **Responsible disclosure** – see [`SECURITY.md`](SECURITY.md) for reporting guidelines and supply-chain expectations.\n- 🪟 **Windows bootstrap script** – run `scripts/bootstrap-windows.ps1` to enable WSL, configure proxies, and install Docker/VS Code with one command.\n\n## Requirements\n\n| Platform      | What you need                                                                                                        |\n| ------------- | -------------------------------------------------------------------------------------------------------------------- |\n| Windows 10/11 | WSL2 (Ubuntu recommended), Docker Desktop with WSL integration, Visual Studio Code, and the Dev Containers extension |\n| macOS / Linux | Docker Engine or Docker Desktop, Visual Studio Code + Dev Containers extension                                       |\n| Everywhere    | Git, ability to clone this repository                                                                                |\n\n\u003e **Tip (Windows)** – enable WSL2 (`wsl --install`), reboot, install Ubuntu from the Microsoft Store, then install Docker Desktop and enable “Use the WSL 2 based engine”. Launch VS Code from inside WSL (`code .`) so the Remote – WSL and Dev Containers extensions can build the workspace container seamlessly.\n\n## Why not Microsoft's devcontainer images?\n\nFull digest pinning, checksum-verified tooling and slimmer bases — the\ncomplete rationale lives in [docs/DESIGN_DECISIONS.md](docs/DESIGN_DECISIONS.md).\n\n## Quick Start\n\n### Option 1: GitHub Codespaces (Fastest - No Setup Required)\n\nLaunch in your browser with one click:\n\n[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/malpanez/ansible-devcontainer-vscode)\n\n**Ready in 30-60 seconds** - No local installation needed!\n\n### Option 2: Local Dev Container\n\n```bash\n# inside WSL2 or any terminal with Docker + VS Code available\ngit clone https://github.com/malpanez/ansible-devcontainer-vscode.git\ncd ansible-devcontainer-vscode\n\n# Pick the stack you need (defaults to Ansible if you skip this step)\n./scripts/use-devcontainer.sh terraform   # or ansible | golang | latex\n# Or use: make switch-terraform\n\ncode .\n\n# When prompted, choose \"Dev Containers: Reopen in Container\"\n# VS Code pulls the published GHCR image for the chosen stack.\n```\n\n\u003e **New Windows laptop?** Run [`scripts/bootstrap-windows.ps1`](scripts/bootstrap-windows.ps1) from an elevated PowerShell prompt (see [`docs/BOOTSTRAP_WINDOWS.md`](docs/BOOTSTRAP_WINDOWS.md)) to enable WSL, configure proxies, and install Docker Desktop / VS Code automatically.\n\n## Pre-commit Strategy\n\nEvery stack ships with a ready-to-use `.pre-commit-config.yaml`. The image bakes in `/usr/local/bin/ensure-precommit`, a tiny helper that:\n\n1. Copies the right template from `/usr/local/share/devcontainer-skel/\u003cstack\u003e/` if the workspace does not provide one.\n2. Runs `uv tool install pre-commit` followed by `uvx pre-commit install -f` and `uvx pre-commit autoupdate`.\n\nThis keeps developer experience consistent:\n\n- **Ansible** builds from `python:3.12-slim-bookworm` (switchable to `ghcr.io/chainguard-images/python:latest` via `BASE_IMAGE`) and installs Ansible + hooks with `uv pip install --system`.\n- **Terraform, Golang, and LaTeX** remain Python-free. They install the `uv` launcher only, so `uvx pre-commit` bootstraps Python on-demand without bloating the image.\n- In VS Code, the `postCreateCommand` simply calls `ensure-precommit`, guaranteeing hooks are installed on day one.\n- CI mirrors the workflow with `uvx pre-commit run --all-files`, so the same hook set gates every PR.\n\n## Available Stacks\n\n| Stack       | Base image                                                  | Approx. size¹ | Included tooling                                                              | Cache mounts                                  |\n| ----------- | ----------------------------------------------------------- | ------------- | ----------------------------------------------------------------------------- | --------------------------------------------- |\n| `ansible`   | `python:3.12-slim-bookworm` (overrideable via `BASE_IMAGE`) | ~650 MB       | uv-managed Python, Ansible + collections, `pre-commit`, `tini`, SSH/git utils | uv cache volume, Ansible Galaxy volume        |\n| `terraform` | multi-stage Debian (bookworm tools + runtime)               | ~240 MB       | Terraform CLI, Terragrunt, TFLint, SOPS, age, `uv` launcher                   | `${workspace}/.terraform.d/plugin-cache` bind |\n| `golang`    | `golang:1.23-alpine` (overrideable via `BASE_IMAGE`)        | ~210 MB       | Go toolchain, git, `uv` launcher, sudo minimal                                | Go module \u0026 build caches                      |\n| `latex`     | `debian:bookworm-slim` + Tectonic                           | ~320 MB       | Tectonic CLI, git/perl helpers, `uv` launcher                                 | `${HOME}/.cache/tectonic` bind                |\n\n¹Sizes are indicative for `linux/amd64` and vary slightly per architecture.\n\n## Why not distroless or Alpine?\n\nSee [docs/DESIGN_DECISIONS.md](docs/DESIGN_DECISIONS.md).\n\n## Image Publishing \u0026 GHCR\n\nImages for every stack are built, scanned, attested and published to\nGHCR by CI. See [docs/IMAGE_PUBLISHING.md](docs/IMAGE_PUBLISHING.md)\nfor tags, pull commands and the publishing pipeline.\n\n## Toolchain Overview\n\nThe table below outlines the tooling shipped with the Ansible stack; Terraform inherits the Python toolchain plus HashiCorp utilities, while Golang and LaTeX stay intentionally lean.\n\n| Area             | Included tooling                                                                                                   |\n| ---------------- | ------------------------------------------------------------------------------------------------------------------ |\n| Provisioning     | Ansible 9, ansible-navigator, Molecule (Docker driver), pytest, pytest-ansible, pytest-testinfra                   |\n| Linting          | ansible-lint (production profile), yamllint, ruff, black, mypy, tflint                                             |\n| Python packaging | [`uv`](https://github.com/astral-sh/uv) for package installation and script execution                              |\n| Collections      | `ansible.posix`, `community.general`, `community.docker`, `kubernetes.core`, `amazon.aws` (see `requirements.yml`) |\n| VS Code          | Recommended extensions, workspace settings, and tasks delivered by the `vscode_config` role                        |\n| Terraform        | Terraform CLI, Terragrunt, TFLint, Checkov (Dev Container installs; CI mirrors tooling)                            |\n\nAll Python dependencies for the Ansible stack are declared in `pyproject.toml` and locked in `uv.lock`. The container installs them system-wide with `uv pip install --system .` during build. If you prefer an isolated virtual environment, run `uv venv .venv \u0026\u0026 uv pip install -e .` inside the container; VS Code will automatically pick up `.venv` thanks to the defaults in `.vscode/settings.json`. Other stacks install only the tooling they need (for example, Terraform pins Terraform/Terragrunt/TFLint via the Dockerfile and installs Checkov with `uv pip install \"checkov\u003e=3.0.0,\u003c4.0.0\"`).\n\n## Pinned Tool Versions\n\nTool versions are pinned at their single source of truth — duplicated\nversion tables rot:\n\n- **Python packages**: `pyproject.toml` + `uv.lock` (exports:\n  `requirements.txt`, `requirements-ansible.txt`)\n- **CLI tools** (terraform, terragrunt, tflint, sops, age, uv, AWS CLI,\n  tectonic): `ARG *_VERSION` at the top of each `devcontainers/*/Dockerfile`,\n  each download verified against its upstream checksum\n- **Base images**: digest-pinned `FROM` lines in the same Dockerfiles\n\n## Local Workflow\n\n1. **Open the repo with VS Code** and reopen it in the Dev Container.\n2. **Run the bootstrap playbook** if you need to reconfigure the workspace manually:\n   ```bash\n   ansible-playbook playbooks/setup-workspace.yml --tags base,ansible\n   ```\n3. **Use the VS Code tasks** (`Ctrl+Shift+B` / `Cmd+Shift+B`):\n   - `Ansible: Lint All`\n   - `Ansible: Syntax Check`\n   - `Ansible: Setup (Check)`\n   - `YAML: Lint All`\n   - `Smoke Tests` (runs `./scripts/run-smoke-tests.sh`)\n   - `Test: Health Check` (`ansible-playbook playbooks/setup-workspace.yml --check`)\n   - `Molecule: Test` (runs the full Molecule + Testinfra scenario)\n   - `Dependencies: Refresh Lock` (invokes `ansible-playbook playbooks/update-dependencies.yml`)\n   - `Pre-commit: Run All`\n4. **Pre-commit** protects commits automatically. Install the hooks once:\n\n   ```bash\n   pre-commit install\n   pre-commit run --all-files\n\n   The hook stack covers `ansible-lint`, `yamllint`, `ruff` (lint + format), and `detect-secrets` (baseline stored in `.secrets.baseline`).\n   ```\n\n## CI/CD\n\nGitHub Actions workflows live under `.github/workflows/`:\n\n- `ci.yml` – runs repository-wide `uvx pre-commit run --all-files`, lints shell and PowerShell scripts, keeps Go/Terraform checks, builds every Dev Container as a multi-arch (`linux/amd64,linux/arm64`) `buildx` job with registry-backed caches, smoke-tests the loaded images, and gates on Trivy CRITICAL findings plus `hadolint`.\n- `lint.yml` – lightweight watcher that reuses the same `uvx pre-commit` pipeline when YAML or Ansible content changes.\n- `release.yml` – publishes tagged releases, reuses the hardened build pipeline, pushes images/SBOMs to GHCR, and signs them with cosign.\n\nAll jobs use Python 3.12 on `ubuntu-latest`. The shared toolchain mirrors the Dev Container ensuring parity between local development and CI.\n\n## Repository Layout\n\n```\n.\n├── .devcontainer/           # Dockerfile + devcontainer.json (uv-enabled)\n├── .github/workflows/       # CI/CD pipelines\n├── .vscode/                 # Local workspace defaults\n├── devcontainers/           # Stack-specific Dockerfiles (ansible, terraform, golang, latex)\n├── inventory/               # Sample localhost inventory\n├── playbooks/               # Ansible playbooks (setup + verification)\n├── roles/                   # Role-based workspace provisioning\n├── pyproject.toml           # Python dependencies (Ansible stack)\n├── uv.lock                  # Locked dependency versions\n├── requirements.yml         # Ansible collections\n└── docs/                   # Documentation (bootstrap guides, roadmap, quick starts)\n```\n\n## Workspace Roles \u0026 Variables\n\n| Role                    | Purpose                                                                                      | Key variables                                                                                                                                                              |\n| ----------------------- | -------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `devcontainer_base`     | System packages, user creation, sudoers hardening, timezone                                  | `devcontainer_base_user`, `devcontainer_base_timezone`                                                                                                                     |\n| `ansible_environment`   | Installs uv, Python requirements, Ansible collections, drops `ansible.cfg` \u0026 `.ansible-lint` | `ansible_environment_config_dir`, `ansible_environment_python_requirements_file`, `ansible_environment_collection_requirements_file`, `ansible_environment_uv_binary_path` |\n| `python_tools`          | Shell PATH tweaks and pytest config                                                          | `python_tools_devcontainer_user`, `python_tools_ansible_config_dir`                                                                                                        |\n| `vscode_config`         | VS Code settings, extensions, tasks                                                          | `vscode_config_workspace_dir`, `vscode_config_python_interpreter_path`                                                                                                     |\n| `devcontainer_template` | Copies Dev Container template into `.devcontainer/`                                          | `devcontainer_template_stack`, `devcontainer_template_root`, `devcontainer_template_target`, `devcontainer_template_clean`                                                 |\n\nOverride defaults in `roles/*/defaults/main.yml` or pass extra vars (`-e variable=value`) to tailor the workspace.\n\n## Testing \u0026 Verification\n\n- `./scripts/run-smoke-tests.sh` — fast smoke test that also asserts Ansible/ansible-core match the pinned requirements.\n- `./scripts/run-ansible-tests.sh` — runs `ansible-test sanity` against every role (set `ANSIBLE_TEST_PYTHON_VERSION` to change the interpreter).\n- `./scripts/smoke-devcontainer-image.sh` — builds a Dev Container image and runs per-stack smoke checks (compatible with Docker Desktop or Podman).\n- `./scripts/smoke-devcontainer-image.sh --stack \u003cname\u003e --build` — builds a stack image (`ansible`, `terraform`, `golang`, `latex`) and runs an end-to-end smoke check used in CI.\n- `molecule test` — spins up Debian with all roles applied and verifies via Testinfra (`molecule/default/tests/test_default.py`).\n- GitHub Actions runs `uvx pre-commit`, targeted playbook/Molecule checks, Go/Terraform tests when relevant, and the hardened container pipeline described above (see `.github/workflows/ci.yml`).\n- See [`docs/`](docs/README.md) for scenario walkthroughs (Terraform Proxmox, LaTeX résumé), corporate network tips, and the Windows bootstrap guide.\n\n## Scenario Playbooks\n\nNeed inspiration for real-world workflows? Start with the scenario guides under [`docs/scenarios`](docs/scenarios):\n\n- [`terraform-proxmox.md`](docs/scenarios/terraform-proxmox.md) — provisions the Proxmox homelab modules using the Terraform stack.\n- [`latex-cv.md`](docs/scenarios/latex-cv.md) — compiles a LaTeX résumé with the LaTeX devcontainer and VS Code tasks.\n\nEach scenario lists the recommended stack, prerequisite commands, and smoke tests so you can adapt them for demos or portfolio work.\n\n## Customising the Environment\n\nExtend a stack profile from your own `.devcontainer/devcontainer.json`,\nadd tools at build time, or layer extra VS Code settings — recipes in\n[docs/CUSTOMISING.md](docs/CUSTOMISING.md).\n\n## Branch Flow\n\n- Feature work should target `develop`.\n- Promotion to `main` is expected to happen from `develop` through the repository automation.\n- Urgent production fixes may target `main` from `hotfix/*`.\n- The repository enforces this path in `.github/workflows/enforce-promotion-path.yml`.\n\n## Dependency Management\n\n- Dependencies are defined in `pyproject.toml` and locked via `uv.lock`. Run `uv lock` whenever you add or upgrade packages.\n- Installations in the Dev Container and CI use `uv pip install --system .` directly from `pyproject.toml`, letting `uv` handle dependency resolution automatically.\n- To test upgrades locally:\n  ```bash\n  uv lock --upgrade package_name\n  uv pip install --system .\n  ```\n  Commit `uv.lock` and the updated `pyproject.toml`.\n- You can automate the lock refresh with `ansible-playbook playbooks/update-dependencies.yml`. Pass `uv_http_proxy`, `uv_https_proxy`, `uv_index_url`, or `uv_no_proxy` as extra vars when running behind a corporate proxy.\n\n## Testing\n\n- `pre-commit run --all-files` – runs yamllint/ansible-lint/ruff/detect-secrets.\n- `./scripts/run-ansible-tests.sh` – executes `ansible-test sanity` for every role (respects `ANSIBLE_TEST_PYTHON_VERSION`, defaults to the pinned Python).\n- `ansible-playbook playbooks/setup-workspace.yml --check` – dry-run validation of the provisioning playbook.\n- `./scripts/run-smoke-tests.sh` – convenience wrapper around `playbooks/test-environment.yml`; pass extra args to forward flags (e.g. `--check`).\n- `./scripts/run-terraform-tests.sh` – formats (`terraform fmt -check`) and validates every Terraform module under `infrastructure/` (skips gracefully when no configs exist). Modules that depend on private providers (for example `infrastructure/proxmox_lab`) are skipped automatically in CI so they can be tested manually when the provider binaries are available.\n- `.trivyignore` documents the temporary CVE allowlist applied to vendor-supplied Terraform tooling (age/sops/terragrunt/tflint). We keep the list short and revisit it whenever upstream ships patched binaries.\n- `ansible-playbook playbooks/update-dependencies.yml` – regenerates `uv.lock` from `pyproject.toml`.\n- `molecule test` – full integration verification.\n  Run `molecule test --scenario-name latex` to exercise the MiKTeX ↔ TeX Live toggle specifically.\n- `tflint --init \u0026\u0026 tflint` – optional Terraform lint (configure rules in `infrastructure/.tflint.hcl`).\n- `checkov -d infrastructure/` – run policy-as-code scans locally; the Terraform container installs Checkov by default.\n\n## Infrastructure Modules\n\n- `infrastructure/README.md` documents the Terraform module layout and how to extend it.\n- `infrastructure/proxmox_lab/` provides a starter module for Proxmox VE VMs (clone existing templates and customise via `virtual_machines`).\n- Copy `proxmox.auto.tfvars.example` into a git-ignored `.tfvars` file and populate secrets via environment variables before planning or applying.\n\n## Secrets Management\n\n- Follow `docs/SECRETS.md` to keep API tokens and credentials out of git while still enabling local automation.\n- Use the shipped `.secrets.baseline` and `pre-commit` hooks to catch accidental leaks before pushing.\n- Populate GitHub repository secrets (e.g. `TF_PM_TOKEN_ID`, `TF_PM_TOKEN_SECRET`) before enabling Terraform plans in CI.\n\n## Security \u0026 Code Scanning\n\nThis repository implements comprehensive security scanning and automated alert management:\n\n- 🔒 **Trivy Scanning**: All container images scanned for CVEs during build\n- 📊 **SARIF Upload**: Security findings integrated into GitHub Security tab\n- 🤖 **Automated Alert Management**: Weekly cleanup of stale/false-positive alerts\n\n**For security reports**: See [`SECURITY.md`](SECURITY.md) for responsible disclosure guidelines.\n\n**Alert Management**:\n\n- Automated workflow runs weekly to clean up stale alerts (90+ days old)\n- Manual trigger available via GitHub Actions → \"Security Alert Management\"\n- Custom dismissal rules in [`.github/scripts/manage-code-scanning-alerts.sh`](.github/scripts/manage-code-scanning-alerts.sh)\n- Configuration file: [`.github/security-alert-exceptions.yml`](.github/security-alert-exceptions.yml)\n\nSee [`.github/scripts/README.md`](.github/scripts/README.md) for automation details and usage.\n\n## Performance Optimizations\n\nRecent optimizations have significantly improved DevContainer startup times:\n\n- **⚡ Fast Startup**: Containers now start in ~30 seconds (previously 2-5 minutes)\n- **🚀 Direct Pull**: git, github-cli (gh), and AWS CLI v2 are pre-installed in base images, eliminating the need for DevContainer features that trigger rebuilds\n- **🔧 Pre-commit Permissions**: Fixed permission issues with gitleaks/Go cache by setting `PRE_COMMIT_HOME` and ensuring proper cache directory ownership\n\n### Using DevContainers in Your Projects\n\nWant to use these production-ready containers in your own Ansible or Terraform projects? See:\n\n- **[INTEGRATION_GUIDE.md](INTEGRATION_GUIDE.md)** - Complete integration guide with setup instructions, pre-commit hooks explanation, and troubleshooting\n- **[examples/](examples/)** - Ready-to-use templates for Ansible collections and Terraform projects\n  - [Ansible Collection Template](examples/ansible-collection/) - Includes [PROMPT_FOR_LLM.md](examples/ansible-collection/PROMPT_FOR_LLM.md) (copy-paste prompt for Claude/ChatGPT)\n  - [Terraform Project Template](examples/terraform-project/) - Includes [PROMPT_FOR_LLM.md](examples/terraform-project/PROMPT_FOR_LLM.md) (copy-paste prompt for Claude/ChatGPT)\n  - [DEVCONTAINER_FEATURES_EXPLAINED.md](examples/DEVCONTAINER_FEATURES_EXPLAINED.md) - Technical explanation of pull vs build behavior\n\n**Quick Setup** (one-line command):\n\n```bash\n# For Ansible Collections\ncurl -fsSL https://raw.githubusercontent.com/malpanez/ansible-devcontainer-vscode/main/examples/ansible-collection/.devcontainer/devcontainer.json -o .devcontainer/devcontainer.json --create-dirs\n\n# For Terraform Projects\ncurl -fsSL https://raw.githubusercontent.com/malpanez/ansible-devcontainer-vscode/main/examples/terraform-project/.devcontainer/devcontainer.json -o .devcontainer/devcontainer.json --create-dirs\n```\n\n## Documentation\n\n- [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) – visual architecture diagrams (Mermaid) showing container build hierarchy, CI/CD pipeline, dependency management flow, and security scanning strategy.\n- `docs/PORTFOLIO.md` captures the automation story behind this repo (useful for blog posts or personal branding).\n- `docs/ROADMAP.md` lists planned enhancements such as extra Dev Containers, CV automation in LaTeX, and onboarding tooling.\n- `docs/CHANGELOG.md` tracks notable changes between releases.\n- `docs/RELEASE_FLOW.md` documents the `develop -\u003e main` promotion path and the `hotfix/* -\u003e main` escape hatch.\n- `docs/SECRETS.md` explains how to handle credentials safely across Terraform and Ansible workflows.\n- [`docs/IMAGE_PUBLISHING.md`](docs/IMAGE_PUBLISHING.md) – GHCR tags, pull commands and the publishing pipeline.\n- [`docs/CUSTOMISING.md`](docs/CUSTOMISING.md) – extending stack profiles and adding tools.\n- [`docs/DESIGN_DECISIONS.md`](docs/DESIGN_DECISIONS.md) – why not Microsoft's images, distroless or Alpine.\n\n## Windows Bootstrap\n\n- Run `scripts/bootstrap-windows.ps1` from an elevated PowerShell session to install Windows Terminal, Git, VS Code, PowerShell 7, WSL2 + Ubuntu, your chosen container engine (Docker Desktop by default or Podman via `-ContainerEngine Podman`), and the VS Code Remote extensions.\n- Optional flags: `-SkipDocker`, `-SkipWSL`, `-ProxyUrl`, `-ProxyBypassList`, and `-PersistProxy` for corporate environments. The script validates winget availability, configures proxies, and reports any reboot requirements. When selecting Podman, use the `-ContainerEngine Podman` switch to avoid Docker Desktop’s commercial licensing requirements.\n- After reboot (if prompted), launch Ubuntu in WSL2, finish the distro bootstrap, clone the repo, and follow the Quick Start.\n\n## Corporate Networks\n\nIf you are behind a VPN, TLS intercept proxy, or an internal Artifactory mirror, review `docs/CORPORATE_NETWORK.md` for guidance on proxy variables, certificate trust, and running the Dev Container in restricted environments.\n\n## Contributing\n\nSee `docs/CONTRIBUTING.md` for branching strategy, lint/test expectations, and pull request guidelines.\n\n## License\n\nDistributed under the MIT License. See `LICENSE` for details.\n\n## 💖 Support This Project\n\nIf this project has helped you or your team, please consider:\n\n- ⭐ Starring the repository\n- 🐛 Reporting bugs or suggesting features\n- 💰 [Sponsoring on GitHub](https://github.com/sponsors/malpanez)\n- 💼 [Hiring me for consulting](mailto:alpanez.alcalde@gmail.com)\n\n## 💼 Enterprise Support \u0026 Training\n\nOrganizations using this in production can get:\n\n- Implementation consulting\n- Custom feature development\n- Team training workshops\n- Priority support with SLA\n\n**Rate:** Competitive day rates for Ireland market\n**Contact:** alpanez.alcalde@gmail.com\n\n---\n\nBuilt with ❤️ by [Miguel Alpañez](https://github.com/malpanez) | DevOps Consultant | Dublin, Ireland\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmalpanez%2Fansible-devcontainer-vscode","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmalpanez%2Fansible-devcontainer-vscode","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmalpanez%2Fansible-devcontainer-vscode/lists"}