Skip to content

fix(ci): consolidate renovate groups (anchore+sigstore, docs-tools+site)#4

Merged
njhensley merged 2 commits into
mainfrom
ci/renovate-consolidate-groups
May 4, 2026
Merged

fix(ci): consolidate renovate groups (anchore+sigstore, docs-tools+site)#4
njhensley merged 2 commits into
mainfrom
ci/renovate-consolidate-groups

Conversation

@njhensley

Copy link
Copy Markdown
Owner

Summary

Two consolidation rules that were authored alongside PR #3 but pushed after that PR was merged, so they didn't make it to main. This PR re-applies them.

  1. Merge anchore + sigstoresupply-chain — both are supply-chain hardening tools (SBOM/scanning/signing) reviewed by the same eyes for the same reasons. Cross-manager glob ["anchore/**", "sigstore/**"] preserves the existing behavior of bundling .settings.yaml entries with their GitHub Actions counterparts.
  2. Merge docs-tools + sitedocs — hugo (.settings.yaml.docs_tools, used by build-versioned-site) and site/package.json (vitepress + vue + mermaid + esbuild + vite) are two halves of one docs build chain. Two packageRules share groupName: "docs" so deps from both managers land in a single renovate/docs PR.

Motivation / Context

Diagnosed when PR #3 merged but the next Renovate run still produced bundles named renovate/anchore, renovate/sigstore, renovate/site, renovate/docs-tools — with the consolidations applied, those become renovate/supply-chain (5 deps) and renovate/docs (4 deps) respectively. Net dashboard delta: 15 awaiting bundles → 12.

Fixes: missing consolidations from PR #3
Related: #3

Type of Change

  • Build/CI/tooling

Component(s) Affected

  • Other: CI / dependency management

Implementation Notes

  • Cherry-picked 8c6269e7 and e28afca1 from the closed ci/renovate-single-schedule branch onto a fresh branch from main. Commits re-signed (-S).
  • No regex or schedule changes; only packageRules consolidation.

Testing

make lint-renovate    # passes against the digest-pinned validator image

After merge + next workflow_dispatch:

  • renovate/anchore + renovate/sigstore → single renovate/supply-chain PR.
  • renovate/site + renovate/docs-tools → single renovate/docs PR.
  • Cooldown still applies (minimumReleaseAge: "3 days" global, 7 days for auto-merge).

Risk Assessment

  • Low — Config-only. Effect is purely on PR bundling/branch slugs; no new auto-merge scope, no schedule changes.

Rollout notes: N/A.

Checklist

  • Linter passes (make lint-renovate)
  • I did not skip/disable tests to make CI green
  • I updated docs (rules' inline comments document cross-manager grouping)
  • Changes follow existing patterns in the codebase
  • Commits are cryptographically signed (git commit -S)
  • Tests pass locally — N/A, no Go code changes
  • I added/updated tests for new functionality — N/A, no Go code changes

njhensley added 2 commits May 4, 2026 14:29
Both Anchore (grype/syft/sbom-action/scan-action) and Sigstore (cosign/
cosign-installer) are supply-chain hardening tools. Their bumps tend to
be reviewed by the same eyes for the same reasons. Bundling them into a
single `supply-chain` group reduces 2 PRs/cycle to 1 without coupling
unrelated tooling.

The cross-manager behavior is preserved — the matchPackageNames glob
still picks up both .settings.yaml entries (via the regex manager:
anchore/grype, anchore/syft, sigstore/cosign) and GitHub Actions
entries (anchore/sbom-action, anchore/scan-action,
sigstore/cosign-installer). Branch slug becomes `renovate/supply-chain`.
The docs build chain has two halves: hugo (.settings.yaml docs_tools,
used by .github/actions/build-versioned-site for versioned landing
pages) and site/package.json (vitepress + vue + mermaid + esbuild +
vite, the main docs site). They're parts of one pipeline; reviewing
their bumps together is the natural workflow.

Both packageRules now share `groupName: "docs"` — Renovate uses the
group slug to determine the branch, so deps from either manager
(custom.regex on .settings.yaml + npm on site/package.json) land in
the single `renovate/docs` PR. Major bumps still split into
`renovate/major-docs` per Renovate's default behavior.
@njhensley njhensley merged commit ff9279d into main May 4, 2026
21 checks passed
njhensley added a commit that referenced this pull request May 4, 2026
#7)

Root cause of the persistent "Repository has changed during renovation"
aborts since PR #4 — Renovate was calling POST /repos/{owner}/{repo}/
statuses/{sha} after each branch creation to write a stability status
check (tied to the cooldown / merge-confidence flow). The workflow's
permissions block had contents:write, pull-requests:write, issues:write
but not statuses:write, so the call 403'd with "integration-
unauthorized". Renovate's error handler maps that internally to
"repository-changed", which is why every prior debugging attempt
(checkout, configurationFile, dry-run env, digest pin) chased the
wrong symptom.

Confirmed via debug log on run 25346172853:
  Request failed with status code 403 (Forbidden):
  POST .../statuses/cf3dc7d1...
  "x-accepted-github-permissions": "statuses=write"
  DEBUG: Caught error setting branch status - aborting
  Error: integration-unauthorized
  DEBUG: Passing repository-changed error up

The earlier hypothesis fixes in PRs #5 and #6 weren't wrong per se
(actions/checkout and configurationFile aren't the cause, and
RENOVATE_DRY_RUN='' isn't either) — they just couldn't have fixed the
underlying permission gap. With statuses:write added, Renovate's
post-branch status-check call should succeed and the run should
complete normally.
njhensley added a commit that referenced this pull request May 13, 2026
Audit findings #2, #3, #4 against generated evidence bundles:
predicate.validatorImages was always null, predicate.validatorCatalogVersion
was always empty, and the pointer's signer block emitted zero-valued
identity/issuer + rekorLogIndex:0 for unsigned bundles — making a real
Rekor log index 0 indistinguishable from 'no Rekor entry' and an
unsigned bundle indistinguishable from one whose signer fields failed
to extract.

Changes:

  - emitRecipeEvidence loads the validator catalog once and feeds it
    to both the BOM (chart refs + validator images) and the
    predicate's ValidatorCatalogVersion + ValidatorImages fields.
    Shared dedupValidatorImages helper collapses the catalog's
    one-entry-per-check duplication (deployment/perf/conformance all
    share images).

  - PointerAttestation.Signer becomes *PointerSigner, omitempty.
    Unsigned bundles emit the attestation entry with no signer block
    at all; signed bundles always carry non-nil Signer with populated
    Identity and Issuer.

  - PointerSigner.RekorLogIndex becomes *int64, omitempty. nil = no
    Rekor entry created (--no-rekor signing path); non-nil = real
    Rekor log index, even when zero (Rekor's first-ever entry occupies
    index 0 and that's a legitimate position a consumer should be
    able to verify).

  - signAndPushBundle's no-push path returns signPushOutcome{} rather
    than signPushOutcome{Sign: &SignResult{}}, matching its existing
    'All fields are nil when --push is absent' comment and letting
    buildPointerInputs do the right nil-check.

Test coverage:

  - pkg/evidence/attestation/pointer_test.go: unsigned bundles MUST
    omit the signer YAML block; signed-without-rekor bundles MUST
    omit rekorLogIndex. Both assertions check rendered YAML, not just
    the struct.

  - pkg/cli/validate_evidence_test.go (new): catalogVersion,
    dedupValidatorImages, validatorImagesForPredicate helpers; and
    buildPointerInputs covers the three outcome shapes (unsigned,
    signed-with-rekor, signed-without-rekor).

Notes:

  - ValidatorImages.Digest remains blank in this PR. The catalog
    records image refs by tag, not by digest; resolving each ref to a
    digest needs a registry round-trip per image, which validate's
    hot path avoids. Audit item #10 (BOM image digests) tracks the
    longer-term resolver path; the same resolver will populate this
    field when it lands.
njhensley added a commit that referenced this pull request May 13, 2026
Audit findings #2, #3, #4 against generated evidence bundles:
predicate.validatorImages was always null, predicate.validatorCatalogVersion
was always empty, and the pointer's signer block emitted zero-valued
identity/issuer + rekorLogIndex:0 for unsigned bundles — making a real
Rekor log index 0 indistinguishable from 'no Rekor entry' and an
unsigned bundle indistinguishable from one whose signer fields failed
to extract.

Changes:

  - emitRecipeEvidence loads the validator catalog once and feeds it
    to both the BOM (chart refs + validator images) and the
    predicate's ValidatorCatalogVersion + ValidatorImages fields.
    Shared dedupValidatorImages helper collapses the catalog's
    one-entry-per-check duplication (deployment/perf/conformance all
    share images).

  - PointerAttestation.Signer becomes *PointerSigner, omitempty.
    Unsigned bundles emit the attestation entry with no signer block
    at all; signed bundles always carry non-nil Signer with populated
    Identity and Issuer.

  - PointerSigner.RekorLogIndex becomes *int64, omitempty. nil = no
    Rekor entry created (--no-rekor signing path); non-nil = real
    Rekor log index, even when zero (Rekor's first-ever entry occupies
    index 0 and that's a legitimate position a consumer should be
    able to verify).

  - signAndPushBundle's no-push path returns signPushOutcome{} rather
    than signPushOutcome{Sign: &SignResult{}}, matching its existing
    'All fields are nil when --push is absent' comment and letting
    buildPointerInputs do the right nil-check.

Test coverage:

  - pkg/evidence/attestation/pointer_test.go: unsigned bundles MUST
    omit the signer YAML block; signed-without-rekor bundles MUST
    omit rekorLogIndex. Both assertions check rendered YAML, not just
    the struct.

  - pkg/cli/validate_evidence_test.go (new): catalogVersion,
    dedupValidatorImages, validatorImagesForPredicate helpers; and
    buildPointerInputs covers the three outcome shapes (unsigned,
    signed-with-rekor, signed-without-rekor).

Notes:

  - ValidatorImages.Digest remains blank in this PR. The catalog
    records image refs by tag, not by digest; resolving each ref to a
    digest needs a registry round-trip per image, which validate's
    hot path avoids. Audit item #10 (BOM image digests) tracks the
    longer-term resolver path; the same resolver will populate this
    field when it lands.
@njhensley njhensley deleted the ci/renovate-consolidate-groups branch June 23, 2026 16:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant