{"id":47686599,"url":"https://github.com/azu/dockerfile-pin","last_synced_at":"2026-04-02T14:52:44.992Z","repository":{"id":347240508,"uuid":"1193294331","full_name":"azu/dockerfile-pin","owner":"azu","description":"A CLI tool that adds @sha256:\u003cdigest\u003e to FROM lines in Dockerfiles and image fields in docker-compose.yml to prevent supply chain attacks.","archived":false,"fork":false,"pushed_at":"2026-03-27T07:37:21.000Z","size":104,"stargazers_count":2,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-27T16:55:26.174Z","etag":null,"topics":["docker","docker-compose","security","tools"],"latest_commit_sha":null,"homepage":"","language":"Go","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/azu.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"azu"}},"created_at":"2026-03-27T04:21:07.000Z","updated_at":"2026-03-27T09:23:49.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/azu/dockerfile-pin","commit_stats":null,"previous_names":["azu/dockerfile-pin"],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/azu/dockerfile-pin","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/azu%2Fdockerfile-pin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/azu%2Fdockerfile-pin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/azu%2Fdockerfile-pin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/azu%2Fdockerfile-pin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/azu","download_url":"https://codeload.github.com/azu/dockerfile-pin/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/azu%2Fdockerfile-pin/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31308447,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T12:59:32.332Z","status":"ssl_error","status_checked_at":"2026-04-02T12:54:48.875Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["docker","docker-compose","security","tools"],"created_at":"2026-04-02T14:52:44.384Z","updated_at":"2026-04-02T14:52:44.971Z","avatar_url":"https://github.com/azu.png","language":"Go","funding_links":["https://github.com/sponsors/azu"],"categories":[],"sub_categories":[],"readme":"# dockerfile-pin\n\nA CLI tool that adds `@sha256:\u003cdigest\u003e` to `FROM` lines in Dockerfiles and `image` fields in docker-compose.yml to prevent supply chain attacks.\n\n## Install\n\n### Homebrew / curl\n\n```bash\n# Download binary (macOS Apple Silicon)\ncurl -sL \"https://github.com/azu/dockerfile-pin/releases/latest/download/dockerfile-pin_darwin_arm64.tar.gz\" | tar xz\nsudo mv dockerfile-pin /usr/local/bin/\n\n# Download binary (Linux amd64)\ncurl -sL \"https://github.com/azu/dockerfile-pin/releases/latest/download/dockerfile-pin_linux_amd64.tar.gz\" | tar xz\nsudo mv dockerfile-pin /usr/local/bin/\n```\n\n### aqua\n\n```bash\naqua init\naqua generate -i azu/dockerfile-pin\naqua i\naqua exec -- dockerfile-pin --help\n```\n\n### Go\n\n```bash\ngo install github.com/azu/dockerfile-pin@latest\n```\n\nSee [GitHub Releases](https://github.com/azu/dockerfile-pin/releases) for all platforms.\n\n## Usage\n\n### Run\n\nAdd digests to Dockerfile `FROM` lines or docker-compose.yml `image` fields.\nBy default, shows changes without modifying files (dry-run).\n\n```bash\n# Preview changes (dry-run, default)\ndockerfile-pin run\n\n# Preview a specific file\ndockerfile-pin run -f path/to/Dockerfile\n\n# Preview multiple files using glob\ndockerfile-pin run --glob '**/Dockerfile*'\n\n# Multiple patterns with brace expansion\ndockerfile-pin run --glob '**/{Dockerfile,Dockerfile.*,docker-compose.yml,compose.yaml}'\n\n# Preview docker-compose.yml\ndockerfile-pin run -f docker-compose.yml\n\n# Actually write changes to files\ndockerfile-pin run --write\n\n# Update existing digests\ndockerfile-pin run --write --update\n```\n\n**Before:**\n\n```dockerfile\nFROM node:20.11.1\nFROM python:3.12-slim AS builder\nFROM scratch\n```\n\n**After:**\n\n```dockerfile\nFROM node:20.11.1@sha256:e06aae17c40c7a6b5296ca6f942a02e6737ae61bbbf3e2158624bb0f887991b5\nFROM python:3.12-slim@sha256:3d5ed973e45820f5ba5e46bd065bd88b3a504ff0724d85980dcd05eab361fcf4 AS builder\nFROM scratch\n```\n\n### Check\n\nValidate that digests are present and exist in the registry.\n\n```bash\n# Check a single Dockerfile\ndockerfile-pin check -f Dockerfile\n\n# Check multiple files\ndockerfile-pin check --glob '**/Dockerfile*'\n\n# Multiple patterns with brace expansion\ndockerfile-pin check --glob '**/{Dockerfile,Dockerfile.*,dockerfile_*.tmpl,docker-compose.yml,compose.yaml}'\n\n# Syntax check only (no registry queries)\ndockerfile-pin check --syntax-only\n\n# JSON output for CI\ndockerfile-pin check --format json\n\n# Ignore specific images\ndockerfile-pin check --ignore-images scratch,mylocal\n```\n\n**Output:**\n\n```\nFAIL  Dockerfile:1    FROM node:20.11.1                                  missing digest\nOK    Dockerfile:3    FROM python:3.12@sha256:abc123...\nSKIP  Dockerfile:5    FROM scratch                                       scratch image\n```\n\nExit code is `1` when any check fails (configurable with `--exit-code`).\n\n## Supported Patterns\n\n### Dockerfiles\n\n| Pattern | Supported |\n|---------|-----------|\n| `FROM image:tag` | Yes |\n| `FROM image:tag AS name` | Yes |\n| `FROM --platform=linux/amd64 image:tag` | Yes |\n| `FROM image:tag@sha256:...` (already pinned) | Skipped (use `--update` to refresh) |\n| `FROM scratch` | Skipped |\n| `FROM \u003cstage-name\u003e` (multi-stage ref) | Skipped |\n| `ARG VERSION=1.0` + `FROM image:${VERSION}` | Yes (expanded from default) |\n| `ARG BASE` + `FROM ${BASE}` (no default) | Skipped with warning |\n| `FROM ghcr.io/org/image:tag` | Yes |\n| `FROM registry:5000/image:tag` | Yes |\n\n### docker-compose.yml\n\n| Pattern | Supported |\n|---------|-----------|\n| `image: node:20` | Yes |\n| `image: node:20@sha256:...` | Skipped (use `--update`) |\n| Service with `build:` directive | Skipped |\n| Service without `image:` key | Skipped |\n\n## CI Integration\n\n### Check (PR validation)\n\nValidate that all images are pinned on every pull request.\n\nWith aqua (if your project already uses aqua, add `azu/dockerfile-pin` to your `aqua.yaml`):\n\n```yaml\n# .github/workflows/dockerfile-check.yml\nname: Dockerfile Digest Check\non: [pull_request]\njobs:\n  check:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: aquaproj/aqua-installer@v3\n        with:\n          aqua_version: v2.45.0\n      - run: dockerfile-pin check\n```\n\nWithout aqua:\n\n```yaml\n# .github/workflows/dockerfile-check.yml\nname: Dockerfile Digest Check\non: [pull_request]\njobs:\n  check:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - name: Install dockerfile-pin\n        run: |\n          curl -sL \"https://github.com/azu/dockerfile-pin/releases/latest/download/dockerfile-pin_linux_amd64.tar.gz\" | tar xz -C /usr/local/bin\n      - run: dockerfile-pin check\n```\n\n`dockerfile-pin check` exits with code 1 if any image is missing a digest.\n\nWhen `-f` and `--glob` are omitted, it auto-detects target files using `git ls-files` filtered by the default glob pattern:\n`**/{Dockerfile,Dockerfile.*,docker-compose*.yml,docker-compose*.yaml,compose.yml,compose.yaml}`\n\nOutside a git repository, it falls back to the same glob pattern with common directories (`node_modules`, `vendor`) excluded.\n\n### Pin (migration)\n\nRun locally to add digests to all Dockerfiles and compose files:\n\n```bash\n# Preview changes\ndockerfile-pin run\n\n# Apply changes\ndockerfile-pin run --write\n```\n\n### Private registries\n\nFor private registries (GCR, GHCR, ECR), configure Docker credentials before running:\n\n```yaml\n      # GHCR\n      - uses: docker/login-action@v3\n        with:\n          registry: ghcr.io\n          username: ${{ github.actor }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n\n      # GCR\n      - uses: google-github-actions/auth@v2\n        with:\n          credentials_json: ${{ secrets.GCP_SA_KEY }}\n      - uses: google-github-actions/setup-gcloud@v2\n      - run: gcloud auth configure-docker\n```\n\n`dockerfile-pin` uses `~/.docker/config.json` for authentication, so any `docker login` or credential helper works.\n\n## How It Works\n\n- Uses [go-containerregistry](https://github.com/google/go-containerregistry) (crane) for registry API calls\n- Uses BuildKit's Dockerfile parser for accurate FROM line parsing\n- `run` resolves digests via HEAD requests (does not count against Docker Hub pull rate limits)\n- `check` verifies digest existence via HEAD requests\n- Authenticates using `~/.docker/config.json` (supports Docker Hub, GHCR, GCR, ECR, etc.)\n\n## Digest Updates\n\n`--update` re-resolves each tag against the registry and replaces the existing digest with the current digest of that tag. The tag itself is not changed.\n\n```bash\n# Re-resolve all pinned digests from the registry\ndockerfile-pin run --write --update\n```\n\nFor automated ongoing digest updates, use [Renovate](https://docs.renovatebot.com/docker/) which understands the `image:tag@sha256:digest` format.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fazu%2Fdockerfile-pin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fazu%2Fdockerfile-pin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fazu%2Fdockerfile-pin/lists"}