Skip to content

plugin: fetch attestation bundles from bundle_url - #2593

Closed
Kunalbehbud wants to merge 1 commit into
terraform-linters:masterfrom
Kunalbehbud:fix/attestation-bundle-url
Closed

plugin: fetch attestation bundles from bundle_url#2593
Kunalbehbud wants to merge 1 commit into
terraform-linters:masterfrom
Kunalbehbud:fix/attestation-bundle-url

Conversation

@Kunalbehbud

Copy link
Copy Markdown
Contributor

Fixes #2591

Root cause

GitHub stopped embedding sigstore bundles in attestation list responses. As @sarahhodne noted in the issue, this matches the documented breaking change ("Remove the bundle property from attestation list responses. ... Use bundle_url to retrieve the attestation bundle"), except it now applies to the 2022-11-28 API version as well. The endpoint currently returns:

{
  "attestations": [
    {
      "repository_id": 245765716,
      "bundle_url": "https://tmaproduction.blob.core.windows.net/attestations/...json.sn?...",
      "initiator": "user",
      "bundle": null
    }
  ]
}

json.Unmarshal unmarshals null into a *bundle.Bundle without error — it just sets the pointer to nil — and VerifyAttestations passes that nil straight to verifier.Verify, which dereferences it in bundle.(*Bundle).TlogEntries. That's the panic in the issue. It also reproduces in this repo's CI: the build workflow on #2592 hit the same panic in Test_Install_withAttestations (run), and the nightly on master will hit it too.

Changes

  1. fetchArtifactAttestations resolves bundle_url. go-github v81 doesn't expose the field, so the endpoint is queried via client.NewRequest/client.Do with a small local struct — this keeps github.ErrorResponse semantics, so isIgnorableAttestationError keeps working for 403/404. When bundle is null or absent, the bundle is downloaded from bundle_url. The blob is served as snappy-compressed JSON (Content-Type: application/x-snappy), so it's snappy-decoded, mirroring what the gh CLI does in getBundle. The download intentionally uses http.DefaultClient: the URL is pre-signed, and API credentials must not be sent to blob storage. If a bundle is ever served uncompressed, the raw body is used as long as it's valid JSON.

  2. VerifyAttestations rejects empty bundles instead of crashing. Bundles are now parsed upfront, and a null bundle returns attestation contains an empty sigstore bundle. Even if the API serves something unexpected again, tflint --init fails with an error rather than a SIGSEGV.

Uses github.com/klauspost/compress/snappy, which is already in the module graph as an indirect dependency, rather than adding a new module.

Tests

  • Test_fetchArtifactAttestations (new, offline via httptest): embedded-bundle passthrough, bundle_url + snappy, bundle_url + uncompressed fallback, null bundle with no URL, download failure.
  • Test_SignatureChecker_VerifyAttestations_errors: new null bundle case — the exact crash input now returns an error.
  • Test_Install_withAttestations (existing, live): panicked before this change exactly as reported; now passes end-to-end against the real API (list → download from bundle_url → decompress → verify).

GitHub stopped embedding sigstore bundles in attestation list
responses: the bundle field is now null and the bundle must be
downloaded from the URL in the bundle_url field, served as
snappy-compressed JSON. Unmarshaling null yields a nil bundle, which
crashed the sigstore verifier with a nil pointer dereference on
every plugin installation that verifies attestations.

Download the bundle from bundle_url when it is not embedded, and
reject empty bundles in VerifyAttestations instead of passing them
to the verifier.

Fixes terraform-linters#2591
Brad-Edwards added a commit to Brad-Edwards/shifter that referenced this pull request Jul 17, 2026
Revert the GITHUB_TOKEN env added in the previous commit: it does not fix
the terraform-lint failure and is in fact a documented trigger.

`tflint --init` nil-panics in sigstore-go bundle.TlogEntries while
verifying the google ruleset's GitHub artifact attestation. A GitHub-side
attestation-bundle change broke this across every recent tflint
(v0.61-v0.63.1), reddening terraform-lint repo-wide including dev; it is
not a rate-limit issue and setting GITHUB_TOKEN makes it worse.

Force PGP signature verification instead (signature = "pgp"), the
maintainer-recommended interim workaround. Keeps supply-chain verification
of the plugin; revert once tflint ships the fix.

Upstream: terraform-linters/tflint#2591, fix PR terraform-linters/tflint#2593.
Refs #1691
Brad-Edwards added a commit to Brad-Edwards/shifter that referenced this pull request Jul 17, 2026
`tflint --init` nil-panics in sigstore-go bundle.TlogEntries while verifying
the google ruleset's GitHub artifact attestation, failing terraform-lint
(and the downstream PR Gate) on this PR. Upstream bug
terraform-linters/tflint#2591: a GitHub-side attestation-bundle change breaks
every recent tflint for all official rulesets, with or without GITHUB_TOKEN.

Force PGP signature verification (signature = "pgp"), the maintainer-
recommended interim workaround; keeps supply-chain verification of the plugin.
Remove once tflint ships the fix (PR terraform-linters/tflint#2593).

Refs #1691
JacobPEvans-personal added a commit to dryvist/tofu-github that referenced this pull request Jul 17, 2026
* fix(ci): pin tflint plugin verification to pgp to unblock linting

GitHub removed the `bundle` field from attestation API responses, so
tflint >=0.61 nil-derefs during `tflint --init` while verifying the
ruleset plugin. The crash happens during plugin download, before any
linting runs, so every PR touching .tf is blocked at the Merge Gate.

Pin `signature = "pgp"`, which still verifies the plugin
cryptographically via the legacy signing key rather than skipping
verification. Marked TEMPORARY with the upstream issue to revert once
terraform-linters/tflint#2593 ships.

Verified against tflint v0.63.1 (the version CI resolves): init
succeeds and lint exits 0.

* ci: run the Terraform job when .tflint.hcl changes

The terraform path filter covered **.tf and the lock file but not the
linter's own config, so a change to .tflint.hcl skipped the Terraform job
entirely -- meaning a tflint config change could never be validated by the
job that runs tflint.

Without this, the signature fix in the previous commit merges with the
Terraform job SKIPPED and no proof it works.
@wata727

wata727 commented Jul 17, 2026

Copy link
Copy Markdown
Member

Thank you for working on this. It looks good to me.

As this issue involves a significant bug fix, it was merged as #2600 to ensure a prompt release. Therefore, I am closing this PR. Thank you for your cooperation.

@wata727 wata727 closed this Jul 17, 2026
tmeijn pushed a commit to tmeijn/dotfiles that referenced this pull request Jul 21, 2026
This MR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [tflint](https://github.com/terraform-linters/tflint) | minor | `0.63.1` → `0.64.0` |

MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot).

**Proposed changes to behavior should be submitted there as MRs.**

---

### Release Notes

<details>
<summary>terraform-linters/tflint (tflint)</summary>

### [`v0.64.0`](https://github.com/terraform-linters/tflint/releases/tag/v0.64.0)

[Compare Source](terraform-linters/tflint@v0.63.1...v0.64.0)

#### What's Changed

##### Enhancements

- cmd: include worker dir for no-range recursive issues by [@&#8203;Zakharden](https://github.com/Zakharden) in [#&#8203;2524](terraform-linters/tflint#2524)
- config: add ignorable rule setting by [@&#8203;Zakharden](https://github.com/Zakharden) in [#&#8203;2525](terraform-linters/tflint#2525)
- formatter(junit): include range in testcase name by [@&#8203;Zakharden](https://github.com/Zakharden) in [#&#8203;2538](terraform-linters/tflint#2538)

##### Bug Fixes

- plugin: fetch attestation bundles from bundle\_url by [@&#8203;Kunalbehbud](https://github.com/Kunalbehbud) in [#&#8203;2593](terraform-linters/tflint#2593)
  - Merged as [#&#8203;2600](terraform-linters/tflint#2600)

##### Chores

- Refactor formatter dispatch into format adapters by [@&#8203;bendrucker](https://github.com/bendrucker) in [#&#8203;2556](terraform-linters/tflint#2556)
- Inline per-format print methods into their adapters by [@&#8203;bendrucker](https://github.com/bendrucker) in [#&#8203;2557](terraform-linters/tflint#2557)
- build(deps): Bump docker/setup-buildx-action from 4.0.0 to 4.1.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2559](terraform-linters/tflint#2559)
- build(deps): Bump github.com/mattn/go-colorable from 0.1.14 to 0.1.15 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2560](terraform-linters/tflint#2560)
- build(deps): Bump golang from 1.26.3-alpine3.23 to 1.26.4-alpine3.23 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2558](terraform-linters/tflint#2558)
- release: Set branch name for Homebrew tap by [@&#8203;wata727](https://github.com/wata727) in [#&#8203;2561](terraform-linters/tflint#2561)
- Extract the shared runner-setup pipeline by [@&#8203;bendrucker](https://github.com/bendrucker) in [#&#8203;2555](terraform-linters/tflint#2555)
- formatter: guard diagnostics with no source range by [@&#8203;bendrucker](https://github.com/bendrucker) in [#&#8203;2562](terraform-linters/tflint#2562)
- docs: add Go install instructions to README by [@&#8203;RoseSecurity](https://github.com/RoseSecurity) in [#&#8203;2563](terraform-linters/tflint#2563)
- build(deps): Bump actions/checkout from 6.0.2 to 6.0.3 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2565](terraform-linters/tflint#2565)
- build(deps): Bump alpine from 3.23.4 to 3.24.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2566](terraform-linters/tflint#2566)
- build(deps): Bump the go-x group with 2 updates by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2567](terraform-linters/tflint#2567)
- build(deps): Bump github.com/sigstore/sigstore-go from 1.1.4 to 1.2.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2568](terraform-linters/tflint#2568)
- fix(install): close download and zip readers by [@&#8203;RoseSecurity](https://github.com/RoseSecurity) in [#&#8203;2564](terraform-linters/tflint#2564)
- build(deps): Bump alpine from 3.24.0 to 3.24.1 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2570](terraform-linters/tflint#2570)
- build(deps): Bump golang.org/x/net from 0.55.0 to 0.56.0 in the go-x group by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2571](terraform-linters/tflint#2571)
- build(deps): Bump github.com/sigstore/sigstore-go from 1.2.0 to 1.2.1 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2572](terraform-linters/tflint#2572)
- build(deps): Bump actions/checkout from 6.0.3 to 7.0.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2579](terraform-linters/tflint#2579)
- build(deps): Bump actions/setup-go from 6.4.0 to 6.5.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2580](terraform-linters/tflint#2580)
- build(deps): Bump golangci/golangci-lint-action from 9.2.1 to 9.3.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2583](terraform-linters/tflint#2583)
- build(deps): Bump goreleaser/goreleaser-action from 7.2.2 to 7.2.3 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2582](terraform-linters/tflint#2582)
- build(deps): Bump actions/attest from 4.1.0 to 4.1.1 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2581](terraform-linters/tflint#2581)
- build(deps): Bump docker/build-push-action from 7.2.0 to 7.3.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2584](terraform-linters/tflint#2584)
- build(deps): Bump golang.org/x/text from 0.38.0 to 0.39.0 in the go-x group by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2585](terraform-linters/tflint#2585)
- build(deps): Bump github.com/sigstore/sigstore-go from 1.2.1 to 1.2.2 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2588](terraform-linters/tflint#2588)
- build(deps): Bump google.golang.org/grpc from 1.81.1 to 1.82.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2587](terraform-linters/tflint#2587)

#### New Contributors

- [@&#8203;Zakharden](https://github.com/Zakharden) made their first contribution in [#&#8203;2524](terraform-linters/tflint#2524)
- [@&#8203;RoseSecurity](https://github.com/RoseSecurity) made their first contribution in [#&#8203;2563](terraform-linters/tflint#2563)
- [@&#8203;Kunalbehbud](https://github.com/Kunalbehbud) made their first contribution in [#&#8203;2593](terraform-linters/tflint#2593)

**Full Changelog**: <terraform-linters/tflint@v0.63.1...v0.64.0>

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this MR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box

---

This MR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNzIuNiIsInVwZGF0ZWRJblZlciI6IjQzLjI3Mi42IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJSZW5vdmF0ZSBCb3QiLCJhdXRvbWF0aW9uOmJvdC1hdXRob3JlZCIsImRlcGVuZGVuY3ktdHlwZTo6bWlub3IiXX0=-->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

tflint --init panics (nil pointer in bundle.TlogEntries) verifying attestations for tflint-ruleset-aws 0.48.0 when GITHUB_TOKEN is set

2 participants