Skip to content

Feat: Implementing Sigstore-A2A verification for A2A Agent Cards#355

Merged
pdettori merged 10 commits into
kagenti:mainfrom
DeanKelly751:feature/sigstore-a2a-signed-card-verification
Jun 11, 2026
Merged

Feat: Implementing Sigstore-A2A verification for A2A Agent Cards#355
pdettori merged 10 commits into
kagenti:mainfrom
DeanKelly751:feature/sigstore-a2a-signed-card-verification

Conversation

@DeanKelly751

@DeanKelly751 DeanKelly751 commented May 12, 2026

Copy link
Copy Markdown

What This PR Delivers

Phase 2b: Sigstore-based Agent Card Verification

  1. Keyless Signing in CI/CD

    • GitHub Actions workflow signs agent cards using GitHub's OIDC identity
    • No long-lived secrets or keys required
    • Uses sigstore-a2a CLI for signing
  2. Cryptographic Verification

    • AgentCard controller verifies Fulcio certificates
    • Validates Rekor transparency log entries
    • Configurable certificate identity allowlist
  3. Supply Chain Provenance

    • SLSA metadata embedded in signed cards
    • Links deployed agents to exact source commits and builds
    • Includes workflow, repository, and commit SHA
  4. Audit Trail

    • Every signature recorded in Sigstore's Rekor transparency log
    • Public, tamper-proof verification
    • Permanent record of what was signed when
  5. Graceful Adoption Mode

    • Unsigned cards allowed but clearly flagged (sigstoreBundleVerified: false)
    • Organizations can migrate incrementally
    • Policy enforcement ready via status.sigstoreBundleVerified field

Implementation Details

Core Changes:

  • AgentCard controller: Added Sigstore bundle verification logic
  • AgentCard status: New fields for verification state (sigstoreBundleVerified, sigstoreIdentity, rekorLogIndex, SLSA provenance)
  • Operator flags: --enable-sigstore-verification, --sigstore-certificate-identity, --sigstore-certificate-oidc-issuer, --sigstore-audit-mode
  • GitHub Actions: .github/workflows/sign-agent-card.yml - OIDC-based signing workflow

Verification Flow:

  1. AgentCard controller fetches agent card from ConfigMap (key: signed-agent-card.json)
  2. If card contains attestations.signatureBundle, verification is attempted
  3. Fulcio certificate validated against configured identity + OIDC issuer
  4. Rekor transparency log entry verified
  5. Status updated with verification result + provenance metadata

Configuration Example:

--enable-sigstore-verification=true
--sigstore-certificate-identity=[https://github.com/ORG/REPO/.github/workflows/WORKFLOW.yml@refs/heads/BRANCH](https://github.com/ORG/REPO/.github/workflows/WORKFLOW.yml@refs/heads/BRANCH)
--sigstore-certificate-oidc-issuer=[https://token.actions.githubusercontent.com](https://token.actions.githubusercontent.com)
--sigstore-audit-mode=false  # true = log failures but don't block

Related:
#327

@kevincogan kevincogan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work on the Sigstore integration. The architecture is solid with clean use of sigstore-go, proper JCS canonicalization, good separation between the fetcher and verifier, and the audit/enforcement mode split is well thought out. Integration tests cover the key paths nicely.

Two items to address, both are quick fixes. See inline comments.

Comment thread .github/workflows/sign-agent-card.yml Outdated
- name: Install sigstore-a2a with pinned a2a-sdk
run: |
uv pip install --system --prerelease=allow "a2a-sdk==0.2.16"
uv pip install --system --prerelease=allow "git+https://github.com/sigstore/sigstore-a2a.git@main"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This installs sigstore-a2a from an unpinned @main branch. For a PR that adds supply-chain verification, the signing toolchain itself should be pinned to a specific commit SHA or tagged release. A compromised or broken main push would silently affect every CI run.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed from:

uv pip install --system --prerelease=allow "git+https://github.com/sigstore/sigstore-a2a.git@main"

To:

uv pip install --system --prerelease=allow
"git+https://github.com/sigstore/sigstore-a2a.git@293f9bd"

Also I added a comment in the workflow to update periodically by checking the commit history.

Comment on lines +115 to +118
rekorURL:
description: RekorURL is reserved for custom transparency log
base URL; the operator primarily uses the trusted root material.
type: string

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This rekorURL field exists in the Helm chart CRD but not in the Go type (SigstoreVerification in agentcard_types.go) or the generated CRD at config/crd/bases/. That means a user can set spec.sigstoreVerification.rekorURL on their AgentCard and the API server will accept it, but the operator will silently ignore it.

Either remove rekorURL from this file to match the generated CRD, or add the corresponding field to the Go type and regenerate. Since the description says "reserved," removing it until it's wired up is the safer option.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Followed your recommendation to remove it as the safer option since it was only "reserved" and not actually wired up.

@DeanKelly751 DeanKelly751 force-pushed the feature/sigstore-a2a-signed-card-verification branch 2 times, most recently from 63b495f to bca169f Compare May 14, 2026 09:11
@DeanKelly751 DeanKelly751 marked this pull request as ready for review May 14, 2026 09:18
@DeanKelly751 DeanKelly751 requested review from a team as code owners May 14, 2026 09:18
@DeanKelly751 DeanKelly751 requested a review from kevincogan May 14, 2026 15:04

@kevincogan kevincogan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@pdettori pdettori left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Summary

Solid Sigstore integration — clean use of sigstore-go, proper JCS canonicalization, good audit/enforcement mode separation, and strong test coverage (~800 LOC). The architecture is well thought out with graceful adoption (unsigned cards allowed but flagged).

However, the PR is behind main with merge conflicts (likely from PR #372 agentcard-into-status and others). A rebase is needed before this can merge.

CI Failures

Check Root Cause Action
Lint mgr.GetEventRecorderFor() deprecated (SA1019) Replace with non-deprecated API
Integration Tests Assertion failures — likely due to conflicts with PR #372's AgentCard status refactoring Rebase onto main, reconcile status changes
E2E Tests Transient: SPIRE helm chart download network EOF Re-run after rebase
Dependency Review in-toto-golang@0.9.0 CVE GHSA-pmwq-pjrm-6p5r (moderate) Update dependency
sign-agent-card Expected: OIDC token unavailable on PR workflows Not a bug — works on push to main

Rebase Recommendation

git fetch origin main
git rebase origin/main
# Conflicts expected in:
#   - internal/controller/agentcard_controller.go
#   - api/v1alpha1/agentcard_types.go
#   - cmd/main.go

After rebase: fix lint issue, update in-toto-golang, re-run CI.

Areas reviewed: Go source, Helm/K8s, CI/Actions, Security, Tests
Commits: 7 commits, all signed-off: yes
CI status: 5 failing (1 infra flake, 1 expected, 3 fixable)

Assisted-By: Claude Code

runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: GitHub Actions should be pinned to full SHA per repo security conventions (the Verify Action Pinning check passes today, but only because new workflow files may not yet be scanned).

Example:

uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4

Same applies to actions/setup-python@v5 and astral-sh/setup-uv@v7 below.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All GitHub Actions in .github/workflows/sign-agent-card.yml have been pinned to full commit SHAs:

All SHAs correspond to the latest stable release tags as of May 28, 2026. This prevents supply chain attacks by ensuring the exact
code version that runs, even if tags are moved.

Comment thread kagenti-operator/cmd/main.go Outdated
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorderFor("agentcard-controller"),
AgentFetcher: agentcard.NewConfigMapFetcher(mgr.GetAPIReader()),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

must-fix: mgr.GetEventRecorderFor() is deprecated (SA1019 staticcheck) — this is what fails the Lint CI check. Replace with the non-deprecated events API.

Note: after rebasing onto current main, check what pattern other controllers in this repo use for event recording.

@DeanKelly751 DeanKelly751 May 28, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Migrated all event recording from the deprecated record.EventRecorder to the new events.EventRecorder API:

Changes made:

  1. Updated controller constructors:
    - mgr.GetEventRecorderFor("agentcard-controller") → mgr.GetEventRecorder("agentcard-controller")
    - Same for AgentRuntimeReconciler and MLflowReconciler
  2. Updated Recorder field type:
    - record.EventRecorder → events.EventRecorder
  3. Migrated all Event() calls to Eventf():
  // Old (deprecated):
  r.Recorder.Event(agentCard, corev1.EventTypeNormal, "SignatureEvaluated", "message")
  
  // New:
  r.Recorder.Eventf(agentCard, nil, corev1.EventTypeNormal, "SignatureEvaluated",
      "VerifySignature", "message") 
  1. Applied consistently across all 3 controllers (17 total Event() calls converted)

Pattern verification: After rebasing onto main, confirmed this matches the pattern used in other controllers in the repo (e.g.,
AgentRuntimeReconciler, MLflowReconciler).

This resolves the SA1019 staticcheck lint failure.

return duration
}

// updateAgentCardStatus persists all status fields atomically with retry.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: The //nolint:gocyclo is understandable given the new Sigstore verification logic added to this function, but the parameter list (now 10 args) is a signal this function is doing too much. Consider extracting Sigstore status update into a helper method in a follow-up PR.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed on the refactoring need. The 10-parameter signature and complexity are clear signals this function is doing too much. We kept
it as-is for this PR to avoid mixing feature work with refactoring, but a follow-up would be valuable.

@DeanKelly751 DeanKelly751 force-pushed the feature/sigstore-a2a-signed-card-verification branch 6 times, most recently from 5bca222 to e9529e2 Compare May 28, 2026 12:01
DeanKelly751 pushed a commit to DeanKelly751/kagenti-operator that referenced this pull request May 28, 2026
Pin all GitHub Actions to full commit SHAs per repository security
conventions to prevent supply chain attacks:

- actions/checkout@v4.2.2 -> 11bd719
- actions/setup-python@v5.3.0 -> 0b93645
- astral-sh/setup-uv@v7.0.0 -> eb1897b
- actions/cache@v4.2.0 -> 1bd1e32
- actions/upload-artifact@v4.5.0 -> 6f51ac0

Addresses review comment from PR kagenti#355.

Signed-off-by: dekelly <dekelly@redhat.com>
@DeanKelly751 DeanKelly751 requested a review from pdettori May 28, 2026 13:13
@pdettori

Copy link
Copy Markdown
Member

CI Failure Analysis

Hi Dean — I took a look at the CI failures and wanted to share what I found in case it helps unblock things. There are 3 independent issues causing the 7 failing checks:


1. Go Compilation Error (affects Build, Lint, Unit Tests, Integration Tests, E2E Tests)

All 5 of these jobs fail due to the same root cause — a type mismatch in internal/agentcard/fetcher.go around line 104:

cannot use res (variable of type *AgentCardData) as *FetchResult value in return statement

It looks like the introduction of the FetchResult type didn't fully propagate through the existing code. There's also a duplicate FetchResult definition (line 278) and some undefined field accesses (Card, CardData, AgentSpiffeID).

Suggestion: You might want to consolidate on a single return type (either AgentCardData or FetchResult), remove the duplicate struct definition, and ensure all referenced fields exist on the chosen type. Running go build ./... locally before pushing should catch these quickly.


2. Dependency Review (security gate)

Two moderate-severity CVEs flagged in github.com/sigstore/rekor@1.4.3:

Advisory Issue
GHSA-273p-m2cw-6833 Nil pointer dereference in COSE canonicalize
GHSA-4c4x-jm2x-pf9j SSRF via public key URL

Suggestion: It may be worth checking for a newer sigstore/rekor release that addresses these. A go get github.com/sigstore/rekor@<patched-version> && go mod tidy should do it. If no patched version is available yet, we can discuss whether to document the accepted risk.


3. sign-agent-card Workflow (OIDC auth failure)

The error is Failed to sign agent card: EOF when reading a line — it appears sigstore-a2a is falling into an interactive browser-based OAuth flow rather than using the GitHub Actions OIDC token.

Suggestion: A few things to check:

  • Confirm the workflow has permissions: id-token: write so the OIDC token can be issued
  • Verify the token is actually written to the file before the sign step (e.g., cat oidc-token.txt | wc -c as a debug step)
  • Check whether sigstore-a2a expects a specific audience claim in the token — GitHub's default audience may differ from what Fulcio expects (sigstore)

Suggested Priority

  1. Fix the fetcher.go type errors — this unblocks 5 of the 7 failing checks in one shot
  2. Upgrade sigstore/rekor — unblocks Dependency Review
  3. Fix OIDC token passing — unblocks the signing workflow

Happy to help dig further into any of these if useful!

@kevincogan kevincogan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CI is failing across all jobs (Build, Lint, Unit Tests, Integration Tests, E2E) due to a single compilation error: FetchResult is declared twice in fetcher.go after the rebase. Your Sigstore version (line 66) and main's SPIFFE version from PR #284 (line 278) need to be merged into one struct. Once that's resolved, everything should go green except sign-agent-card (which is expected to fail on PR workflows due to OIDC token unavailability).

Comment on lines +65 to +71
// FetchResult is the outcome of fetching agent card content from ConfigMap and/or HTTP.
type FetchResult struct {
Card *agentv1alpha1.AgentCardData
// RawSignedAgentCardJSON is non-nil when the source document was a SignedAgentCard
// (agentCard + attestations). Used for Sigstore bundle verification.
RawSignedAgentCardJSON []byte
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

must-fix: FetchResult is declared twice in this file - here at line 66 and again at line 278. The second declaration came from main (PR #284's SpiffeFetcher with CardData + AgentSpiffeID), and this one is yours (with Card + RawSignedAgentCardJSON). Go won't compile with duplicate type names in the same package - this is what's failing all CI jobs.

Merge them into a single struct:

type FetchResult struct {
     CardData               *agentv1alpha1.AgentCardData
     AgentSpiffeID          string
     RawSignedAgentCardJSON []byte
 }

Then update your references from res.Card to res.CardData and remove the duplicate at line 278. That single change should fix all 10 compilation errors across Build, Lint, Unit Tests, Integration Tests, and E2E.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merged the two FetchResult definitions exactly as you suggested:

  // Line 66 - now contains all fields from both definitions
  type FetchResult struct {
      CardData               *agentv1alpha1.AgentCardData
      AgentSpiffeID          string
      RawSignedAgentCardJSON []byte
  }

@DeanKelly751 DeanKelly751 force-pushed the feature/sigstore-a2a-signed-card-verification branch from 14c2296 to 4e53ca2 Compare May 28, 2026 15:06
@DeanKelly751 DeanKelly751 requested a review from kevincogan May 28, 2026 15:06

@kevincogan kevincogan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work, just a few updates needed. The FetchResult duplicate is fixed, but there are still two build-breaking issues:

  1. Six .Event() calls that need to be .Eventf() - the events.EventRecorder interface only has Eventf(regarding, related, eventtype, reason, action, note). Three in agentcard_controller.go (lines 187, 314, 416) and three in agentruntime_controller.go (lines 236, 243, 841). These are pre-existing calls from main that weren't converted when the Recorder type was changed.

  2. Test files still use FetchResult.Card instead of CardData - fetcher_test.go, agentcard_controller_test.go, signature_verification_test.go, identity_binding_integration_test.go, and sigstore_verification_integration_test.go all reference the old field name.

Once both are fixed, CI should go green (except sign-agent-card which is expected to fail on PR workflows).

client.Client
Scheme *runtime.Scheme
Recorder record.EventRecorder
Recorder events.EventRecorder

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

must-fix: Changing the Recorder type from record.EventRecorder to events.EventRecorder means all calls must use Eventf() instead of Event(). Your new Sigstore code correctly uses Eventf, but there are 6 pre-existing .Event() calls on main that also need converting since they now won't compile:

agentcard_controller.go:

  • Line 187: r.Recorder.Event(agentCard, ..., "Deprecated", ...)
  • Line 314: r.Recorder.Event(agentCard, ..., "CardContentChanged", ...)
  • Line 416: r.Recorder.Event(agentCard, ..., "FallbackToHTTP", ...)

agentruntime_controller.go:

  • Line 236: r.Recorder.Event(rt, ..., "SkillsNotMounted", ...)
  • Line 243: r.Recorder.Event(rt, ..., "SkillsNotMounted", ...)
  • Line 841: r.Recorder.Event(rt, ..., "FallbackToHTTP", ...)

These existed on main with the old record.EventRecorder type. Since your PR changes the type, they need to be converted too.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All calls now use the correct Eventf(regarding, related, eventtype, reason, action, note, ...)
signature required by the events.EventRecorder interface. The code compiles cleanly with these
changes.

Comment on lines +48 to +49
g.Expect(result.Card.Name).To(Equal("test-agent"))
g.Expect(result.Card.Version).To(Equal("1.0"))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

must-fix: FetchResult.Card was renamed to FetchResult.CardData in the struct merge fix, but all the test references still use .Card. This affects this file throughout, plus agentcard_controller_test.go (lines 53, 70, 72), signature_verification_test.go, identity_binding_integration_test.go, and sigstore_verification_integration_test.go. All result.Card and Card: struct literals need to become result.CardData and CardData:.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed - All test references have been updated from result.Card to result.CardData:

fetcher_test.go: All 20+ references updated (lines 48, 49, 66, 143-145, 165-166, 195-197, 253-290,
313-314, 336, 367, 400)

agentcard_controller_test.go: All struct literals updated from Card: to CardData: (lines 53, 70,
72)

signature_verification_test.go: Mock return updated to CardData: (line 1102)

All tests now compile and pass. The field rename from Card to CardData is now consistent across the
entire codebase.

return nil, m.err
}
return m.cardData, nil
return &agentcard.FetchResult{Card: m.cardData}, nil

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

must-fix: Should be CardData not Card to match the merged FetchResult struct definition.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed - Changed to CardData: to match the FetchResult struct definition.

Comment on lines 360 to 375

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should-fix: The mTLS path does raw json.Unmarshal directly into AgentCardData, bypassing decodeAgentCardPayload() which the HTTP and ConfigMap paths use. If an agent serves a SignedAgentCard envelope ({"agentCard": {...}, "attestations": {...}}) over the TLS port, this will unmarshal into an empty AgentCardData (unknown top-level keys are silently ignored), and RawSignedAgentCardJSON is never set, so Sigstore verification is silently skipped.

Use decodeAgentCardPayload(body) here and attach the AgentSpiffeID from TLS afterwards, same as the HTTP path does.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mTLS path now uses decodeAgentCardPayload(body) and attaches the AgentSpiffeID
from TLS afterwards:

  result, err := decodeAgentCardPayload(body)
  if err != nil {
      return nil, err
  }

  agentSpiffeID := extractSpiffeIDFromTLS(tlsState)
  result.AgentSpiffeID = agentSpiffeID

This matches the HTTP path pattern and ensures SignedAgentCard envelopes are properly decoded with
RawSignedAgentCardJSON set for Sigstore verification.

@DeanKelly751 DeanKelly751 requested a review from kevincogan May 29, 2026 09:39

@kevincogan kevincogan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! All build breaking issues are resolved. FetchResult struct is unified, .Event() calls converted to .Eventf(), and test references updated.

@pdettori

pdettori commented Jun 8, 2026

Copy link
Copy Markdown
Member

All review comments have been addressed — nice work on the fixes.

However, the PR currently has merge conflicts that are preventing CI from running and blocking merge. Could you rebase onto main to resolve them?

Once conflicts are resolved and CI passes, we should be good to merge.

DeanKelly751 pushed a commit to DeanKelly751/kagenti-operator that referenced this pull request Jun 8, 2026
Pin all GitHub Actions to full commit SHAs per repository security
conventions to prevent supply chain attacks:

- actions/checkout@v4.2.2 -> 11bd719
- actions/setup-python@v5.3.0 -> 0b93645
- astral-sh/setup-uv@v7.0.0 -> eb1897b
- actions/cache@v4.2.0 -> 1bd1e32
- actions/upload-artifact@v4.5.0 -> 6f51ac0

Addresses review comment from PR kagenti#355.

Signed-off-by: dekelly <dekelly@redhat.com>
@DeanKelly751 DeanKelly751 force-pushed the feature/sigstore-a2a-signed-card-verification branch from dea6913 to 56125fd Compare June 8, 2026 15:24
@RyanJenkins99

Copy link
Copy Markdown

/run-e2e

@DeanKelly751 DeanKelly751 force-pushed the feature/sigstore-a2a-signed-card-verification branch from 4c948ed to 36416de Compare June 9, 2026 09:28
@DeanKelly751

Copy link
Copy Markdown
Author

@pdettori everything is ready to merge :)

@pdettori pdettori left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CI Failure Analysis

All 7 failing checks trace to 3 distinct root causes — fixing them should unblock the entire CI pipeline.

Root Cause 1: Compilation Error (blocks 5 jobs: Build, Lint, Unit Tests, Integration Tests, E2E Tests)

agentruntime_controller.go:196:15: r.Recorder.Event undefined (type "k8s.io/client-go/tools/events".EventRecorder has no field or method Event)
agentruntime_controller.go:202:15: r.Recorder.Event undefined (type "k8s.io/client-go/tools/events".EventRecorder has no field or method Event)

The PR correctly migrates Recorder from record.EventRecorder to events.EventRecorder and converts most Event() calls to Eventf(). However, two calls were missed — the Istio mesh enrollment events in agentruntime_controller.go (around lines 193-202 on HEAD).

These are the two calls that need conversion:

// Currently (line ~194):
r.Recorder.Event(rt, corev1.EventTypeWarning, "IstioMeshLabelError", istioErr.Error())
// Should be:
r.Recorder.Eventf(rt, nil, corev1.EventTypeWarning, "IstioMeshLabelError",
    "EnsureIstioMesh", istioErr.Error())

// Currently (line ~200):
r.Recorder.Event(rt, corev1.EventTypeNormal, "IstioMeshEnrolled",
    fmt.Sprintf("Namespace %s labeled for Istio ambient mesh", rt.Namespace))
// Should be:
r.Recorder.Eventf(rt, nil, corev1.EventTypeNormal, "IstioMeshEnrolled",
    "EnsureIstioMesh", "Namespace %s labeled for Istio ambient mesh", rt.Namespace)

Root Cause 2: Vulnerable Dependency (blocks Dependency Review)

github.com/sigstore/timestamp-authority/v2@2.0.3 is flagged for GHSA-xm5m-wgh2-rrg3 (Improper Certificate Validation in verifier, moderate severity).

Fix: Bump github.com/sigstore/timestamp-authority/v2 to a patched version. Check the advisory for the minimum fixed version, then:

cd kagenti-operator && go get github.com/sigstore/timestamp-authority/v2@latest && go mod tidy

Root Cause 3: Interactive Prompt in CI (blocks sign-agent-card)

The sign-agent-card workflow fails because sigstore-a2a sign prompts for an interactive verification code (Enter verification code:) and receives EOF in the non-interactive CI environment.

Fix: Ensure the OIDC identity token from GitHub Actions is passed non-interactively. The workflow should either:

  • Use --identity-token flag with the token from $ACTIONS_ID_TOKEN_REQUEST_TOKEN
  • Or ensure oidc-token.txt is correctly piped to the signing command's stdin

See: GitHub's OIDC documentation for Actions


Suggested priority: Fix #1 first (2-line change, unblocks 5 of 7 jobs), then #2 (dependency bump), then #3 (workflow config).

Assisted-By: Claude Code

DeanKelly751 pushed a commit to DeanKelly751/kagenti-operator that referenced this pull request Jun 10, 2026
Pin all GitHub Actions to full commit SHAs per repository security
conventions to prevent supply chain attacks:

- actions/checkout@v4.2.2 -> 11bd719
- actions/setup-python@v5.3.0 -> 0b93645
- astral-sh/setup-uv@v7.0.0 -> eb1897b
- actions/cache@v4.2.0 -> 1bd1e32
- actions/upload-artifact@v4.5.0 -> 6f51ac0

Addresses review comment from PR kagenti#355.

Signed-off-by: dekelly <dekelly@redhat.com>
@DeanKelly751 DeanKelly751 force-pushed the feature/sigstore-a2a-signed-card-verification branch from 36416de to 481dc34 Compare June 10, 2026 12:01
@DeanKelly751 DeanKelly751 requested a review from kevincogan June 10, 2026 15:06
DeanKelly751 pushed a commit to DeanKelly751/kagenti-operator that referenced this pull request Jun 10, 2026
Pin all GitHub Actions to full commit SHAs per repository security
conventions to prevent supply chain attacks:

- actions/checkout@v4.2.2 -> 11bd719
- actions/setup-python@v5.3.0 -> 0b93645
- astral-sh/setup-uv@v7.0.0 -> eb1897b
- actions/cache@v4.2.0 -> 1bd1e32
- actions/upload-artifact@v4.5.0 -> 6f51ac0

Addresses review comment from PR kagenti#355.

Signed-off-by: dekelly <dekelly@redhat.com>
@DeanKelly751 DeanKelly751 force-pushed the feature/sigstore-a2a-signed-card-verification branch from 2efa0c7 to 8dbc0bc Compare June 10, 2026 18:12
@pdettori

Copy link
Copy Markdown
Member

@DeanKelly751 great job on fixing the issues pointed out - CI has just been fixed and we are finally getting green runs again - please rebase from upstream main and force push so we can check now with full CI

@kevincogan kevincogan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DeanKelly751 Really nice work, the PR is almost there! After the three RBAC marker fixes below, run make manifests to regenerate config/rbac/role.yaml and include the updated file in your commit. The E2E Test should pass after this.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This controller uses events.EventRecorder (from k8s.io/client-go/tools/events) which writes to the events.k8s.io API group, not core. Change groups=core to groups=events.k8s.io. This is the cause of the E2E failure, the controller gets forbidden when trying to emit events like SkillAnnotationParseError.

Replace with:
// +kubebuilder:rbac:groups=events.k8s.io,resources=events,verbs=create;patch

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All three RBAC markers have been updated:

  • agentruntime_controller.go -- changed groups=core to groups=events.k8s.io for events

  • agentcard_controller.go -- added // +kubebuilder:rbac:groups=events.k8s.io,resources=events,verbs=create;patch

  • mlflow_controller.go -- added // +kubebuilder:rbac:groups=events.k8s.io,resources=events,verbs=create;patch

Ran make manifests to regenerate config/rbac/role.yaml -- the updated file is included in the commit.

// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;update;patch
// +kubebuilder:rbac:groups=apps,resources=statefulsets,verbs=get;list;watch;update;patch
// +kubebuilder:rbac:groups=core,resources=configmaps,verbs=get;list;watch
// +kubebuilder:rbac:groups=agents.x-k8s.io,resources=sandboxes,verbs=get;list;watch

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing events RBAC marker. This controller uses events.EventRecorder and emits 15+ event types but has no permission to do so.

Replace with :
// +kubebuilder:rbac:groups=agents.x-k8s.io,resources=sandboxes,verbs=get;list;watch
// +kubebuilder:rbac:groups=events.k8s.io,resources=events,verbs=create;patch

// +kubebuilder:rbac:groups=mlflow.opendatahub.io,resources=mlflowexperiments,verbs=get;list;watch;update
// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=roles,verbs=create;get;list;watch;update
// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=rolebindings,verbs=create;get;list;watch;update
// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;update;patch

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue uses events.EventRecorder but missing the RBAC marker.

Replace with:
// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;update;patch
// +kubebuilder:rbac:groups=events.k8s.io,resources=events,verbs=create;patch

dekelly added 10 commits June 11, 2026 10:46
Implement Sigstore (sigstore-a2a) bundle verification for agent cards
using the sigstore-go library with production TUF root, certificate
identity validation, and Rekor transparency log verification.

**Core Verification**
- Verify SignedAgentCard bundles using sigstore-go verify.NewVerifier
- Validate Fulcio certificate identity against expected GitHub workflow
- Confirm Rekor transparency log inclusion
- Extract SLSA provenance (repository, commit SHA) from bundles
- Support both current (attestations) and legacy (verificationMaterial) formats
- Use JCS (RFC 8785) canonicalization for artifact bytes

**Configuration**
- CLI flags: --enable-sigstore-verification, --sigstore-audit-mode,
  --sigstore-certificate-identity, --sigstore-certificate-oidc-issuer
- Per-AgentCard identity override via spec.sigstoreVerification
- Support custom TUF trust roots via ConfigMap
- Staging TUF support for testing (--sigstore-staging)

**Status & Observability**
- Status fields: sigstoreBundleVerified, sigstoreIdentity, rekorLogIndex,
  slsaRepository, slsaCommitSHA
- SigstoreVerified condition with reasons: SigstoreVerified,
  SigstoreVerificationFailed, SigstoreVerificationFailedAudit,
  SigstoreBundleNotFound
- Kubernetes Events: SigstoreVerified (Normal), SigstoreVerificationFailed
  (Warning), SigstoreBundleNotFound (Warning)
- Prometheus metrics: kagenti_sigstore_verification_total{result},
  kagenti_sigstore_verification_duration_seconds,
  kagenti_sigstore_trusted_root_age_seconds

**Enforcement**
- Audit mode: log failures without blocking reconciliation
- Enforcement mode: reject cards with invalid/missing bundles
- NetworkPolicy integration: verified label requires both JWS and Sigstore
- Graceful adoption: absent bundles (plain agent cards) marked as Absent

**CI Integration**
- GitHub Actions workflow: .github/workflows/sign-agent-card.yml
- Uses sigstore-a2a Python library to sign example agent card
- OIDC token from GitHub Actions for keyless signing
- Publishes signed card as workflow artifact

**Helm Chart**
- New values: sigstore.enabled, sigstore.auditMode,
  sigstore.certificateIdentity, sigstore.certificateOIDCIssuer,
  sigstore.staging, sigstore.trustedRoot
- Manager deployment updated to pass Sigstore flags

**Testing**
- 6 integration test cases: valid bundle, absent bundle, audit mode,
  enforcement mode, SLSA extraction, per-card identity override
- Unit tests for parseProvenance, parseSignedAgentCardStructure
- Example signed agent card in examples/ci-agent-card.json

**Documentation**
- Manual E2E test guide for Sigstore verification
- Inline code comments for Sigstore initialization and verification flow
- Webhook configuration comment for local testing without certificates

**Code Review Fixes**
- Add kustomize patch for webhook namespace/object selectors (W-1 HIGH)
- Include Sigstore in NetworkPolicy label propagation (P-2 MEDIUM)
- Emit Kubernetes Events for all Sigstore paths (P-3 MEDIUM)
- Handle infrastructure errors in enforcement mode (M-3 MEDIUM)
- Clear Sigstore status when verification disabled (P-6 LOW)
- Remove unused RekorURL CRD field (CRD-1 LOW)
- Allow validation webhooks to be disabled via ENABLE_WEBHOOKS=false

Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
Signed-off-by: dekelly <dekelly@redhat.com>
- Split long error messages in cmd/main.go to stay under 120 char limit
- Add nolint:gocyclo directive for updateAgentCardStatus (TODO: refactor)

Signed-off-by: dekelly <dekelly@redhat.com>
Signed-off-by: dekelly <dekelly@redhat.com>
  - Pin sigstore-a2a to commit SHA 293f9bd instead of @main for reproducibility
  - Remove non-functional rekorURL field from Helm chart CRD to match Go types

Signed-off-by: dekelly <dekelly@redhat.com>
Migrate all event recording from deprecated record.EventRecorder to the
new events.EventRecorder API:

- Update mgr.GetEventRecorderFor() → mgr.GetEventRecorder()
- Change Recorder type from record.EventRecorder to events.EventRecorder
- Convert all Event() calls to Eventf() with new signature:
  Eventf(regarding, related, eventtype, reason, action, note, args...)
- Add descriptive action parameter to all event calls

Also update in-toto-golang dependency from v0.9.0 to v0.11.0 to address
CVE GHSA-pmwq-pjrm-6p5r.

Fixes SA1019 staticcheck linting errors.

Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
Signed-off-by: dekelly <dekelly@redhat.com>
Pin all GitHub Actions to full commit SHAs per repository security
conventions to prevent supply chain attacks:

- actions/checkout@v4.2.2 -> 11bd719
- actions/setup-python@v5.3.0 -> 0b93645
- astral-sh/setup-uv@v7.0.0 -> eb1897b
- actions/cache@v4.2.0 -> 1bd1e32
- actions/upload-artifact@v4.5.0 -> 6f51ac0

Addresses review comment from PR kagenti#355.

Signed-off-by: dekelly <dekelly@redhat.com>
Resolves compilation errors caused by duplicate FetchResult struct
definitions after rebase with main branch (PR kagenti#284). Merged the two
FetchResult types into a single struct with all required fields:
CardData, AgentSpiffeID, and RawSignedAgentCardJSON.

Changes:
- Consolidated FetchResult definitions from lines 66 and 278
- Updated all references from Card to CardData field
- Fixed function signatures in fetchAgentCardFromPath
- Updated controller code to extract CardData from FetchResult

This fixes 5 failing CI checks: Build, Lint, Unit Tests, Integration
Tests, and E2E Tests.

Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
Signed-off-by: dekelly <dekelly@redhat.com>
- Update all test references from result.Card to result.CardData throughout
  test files to match the FetchResult.CardData field rename
- Fix test mock returns to use CardData instead of Card in struct literals
- Update FakeRecorder to use events.FakeRecorder instead of record.FakeRecorder
  to match the events.EventRecorder interface
- Fix stubCardFetcher to return FetchResult instead of AgentCardData directly

All tests now compile and pass. Event() calls were already converted to Eventf()
in a previous commit, and the mTLS path already uses decodeAgentCardPayload().

Signed-off-by: dekelly <dekelly@redhat.com>
- Add missing space before opening brace in cmd/main.go
- Align FetchResult struct fields in fetcher.go
- Fix comment indentation in agentcard_controller.go

Signed-off-by: dekelly <dekelly@redhat.com>
…ore integration tests

Signed-off-by: dekelly <dekelly@redhat.com>
@DeanKelly751 DeanKelly751 force-pushed the feature/sigstore-a2a-signed-card-verification branch from 8dbc0bc to 98abe62 Compare June 11, 2026 10:00

@kevincogan kevincogan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DeanKelly751 LGTM, and all green. Nice work! This looks ready to merge pending any feedback from @pdettori

@kevincogan kevincogan requested a review from pdettori June 11, 2026 10:58

@pdettori pdettori left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@pdettori pdettori merged commit 17b0e60 into kagenti:main Jun 11, 2026
20 of 21 checks passed
@github-project-automation github-project-automation Bot moved this from New /:ToDo to Done in Kagenti Issue Prioritization Jun 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

5 participants