Skip to content

About

No description, website, or topics provided.

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

Latest commit

 

History

28 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

attest-vm-image

A GitHub Action that inspects a finished QCOW2 VM disk image and produces auditable evidence about what is inside it, then optionally signs that evidence.

Run it immediately after an image build — ideally in the same job — so the exact bytes the builder emitted are the bytes that get inspected and attested. The action is independent of any one builder: it accepts a QCOW2 disk from Distrobuilder, mkosi, Packer, bootc/Image Builder, or anything else.

The action never modifies the input image. It validates the disk structure, inspects the filesystem read-only inside an isolated libguestfs appliance, generates a Software Bill of Materials (SBOM), scans that SBOM for known vulnerabilities, runs contamination checks for state that should not ship in a reusable image, records everything in a versioned validation predicate, and computes immutable digests. When explicitly asked, it signs and publishes attestations.

The resulting evidence lets a later system or a human reviewer establish which exact artifact was evaluated, what software it contained, which policy was applied, what passed or failed, which workflow produced the evidence, and which identity signed it.

Usage

The default signer: none mode writes checksums, the SBOM, the vulnerability and validation reports, the validation predicate, and a versioned evidence manifest without signing, and needs only contents: read. Once an earlier step in the job has built your image, add the action:

jobs:
  attest:
    runs-on: ubuntu-24.04
    permissions:
      contents: read
    steps:
      # An earlier step in this job builds your image at build/disk.qcow2.
      - uses: meigma/attest-vm-image@v1
        with:
          disk-path: build/disk.qcow2
          fail-on-severity: none
          signer: none

To sign and publish attestations, add three job permissions and set signer: github:

permissions:
  contents: read
  id-token: write
  attestations: write
steps:
  - uses: meigma/attest-vm-image@v1
    with: { disk-path: build/disk.qcow2, signer: github }

To create portable bundles with GitHub Actions identity but without GitHub's attestation API, grant only OIDC and select public Sigstore keyless signing:

permissions:
  contents: read
  id-token: write
steps:
  - uses: meigma/attest-vm-image@v1
    with: { disk-path: build/disk.qcow2, signer: sigstore-keyless }

Keyless signing permanently publishes the repository, workflow, ref, commit, run, and certificate identity to public Sigstore transparency services. Use an encrypted Cosign or KMS key instead when that identity must remain private.

Private repositories that cannot use GitHub's attestation API can produce portable, offline bundles with an encrypted Cosign key instead. Keep the private key and password in GitHub Secrets and distribute cosign.pub to verifiers through an independently trusted channel:

permissions:
  contents: read
steps:
  - uses: meigma/attest-vm-image@v1
    env:
      COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
      COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
    with:
      disk-path: build/disk.qcow2
      signer: cosign-key
      signing-key: env://COSIGN_PRIVATE_KEY

The same portable, no-public-log bundle contract is available with signer: kms for non-exportable AWS KMS, Google Cloud KMS, Azure Key Vault, HashiCorp Vault Transit, and OpenBao Transit keys. Authenticate to the provider in a preceding step and pass only an immutable or versioned KMS URI; see the signing guide for the allowlisted forms and provider status.

Signing has repository plan and visibility requirements, and a failing result is never signed — see Publish signed attestations. For a complete, runnable workflow, start with the Getting started tutorial. Every input and output is listed in the reference.

Requirements at a glance

  • A Linux x64 GitHub-hosted runner (arm64 is best-effort); non-Linux platforms and other architectures fail closed.
  • The action installs qemu-utils and libguestfs-tools itself at runtime, so the runner must permit apt-get and passwordless sudo — hosted ubuntu-* runners qualify by default.
  • Outbound network access to github.com for the pinned syft, grype, and external-signing cosign binaries, to the Grype vulnerability database, to the GitHub attestation API for signer: github, and to GitHub OIDC plus the public Sigstore services for signer: sigstore-keyless, or to the selected provider endpoint for signer: kms.

The full runner, privilege, and network catalog is in the reference.

Documentation

Development

Tooling is pinned by mise and tasks run through moon.

mise install         # provision the pinned toolchain (Node, Python, uv, moon)
moon run root:check  # the full CI gate: format-check, lint, test, check-dist, audit

Useful project commands:

moon run root:format   # prettier --write
moon run root:lint     # eslint
moon run root:test     # jest
moon run root:package  # rebuild dist/
moon run docs:build    # build the documentation site strictly
moon run docs:serve    # serve the documentation site locally

The bundled action (dist/index.js) is committed — that is what action.yml executes. After changing anything under src/, run moon run root:package and commit the refreshed dist/ in the same change; CI's check-dist task rebuilds the bundle and fails if the committed copy is stale.

The audit step runs npm audit at the strict --audit-level=low threshold through scripts/audit.mjs (allowlist currently empty — any advisory fails the gate). package.json carries an overrides block forcing @sigstore/sign@^5 and @sigstore/bundle@^5 under @actions/attest, resolving the fixed @sigstore/core@^4.0.1 (GHSA-jfc7-64v2-mr8c); a unit test asserts the lockfile resolves the patched majors so a silent regression fails in jest.

See CONTRIBUTING.md and SECURITY.md.

License

Dual-licensed under MIT or Apache-2.0, at your option. Upstream template code is MIT (LICENSE.upstream).

About

No description, website, or topics provided.

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages