Skip to content

feat(golang): add Go implementation using x402 v2 protocol with testable architecture#64

Closed
0xfakeSpike wants to merge 12 commits intogoogle-agentic-commerce:mainfrom
0xfakeSpike:main
Closed

feat(golang): add Go implementation using x402 v2 protocol with testable architecture#64
0xfakeSpike wants to merge 12 commits intogoogle-agentic-commerce:mainfrom
0xfakeSpike:main

Conversation

@0xfakeSpike
Copy link

Summary

Add complete Go implementation of x402 A2A payment protocol with improved architecture for testability and comprehensive test coverage.

Changes

Features

  • Add Go implementation using x402 v2 protocol
  • Implement merchant and client components
  • Add example implementations for both merchant and client

Refactoring

  • Introduce interface abstraction (ResourceServer, ExtensionChecker) for dependency injection
  • Refactor BusinessOrchestrator to support testable architecture
  • Maintain backward compatibility with existing code

Fixes

  • Ensure errors are properly returned even when state transitions succeed
  • Fix error propagation in payment flow (ensureExtension, handlePaymentSubmitted)

Testing

  • Add comprehensive orchestrator tests with mock dependencies
  • Complete payment extraction test functions (payload, requirements, receipts)
  • Add utility function tests (ToMap, FromMap, ToSlice)

Files Changed

  • 37 files changed, 4270 insertions(+)
  • Core merchant/client implementation
  • State management and extraction utilities
  • Example applications
  • Comprehensive test suite

…jection

- Add ResourceServer and ExtensionChecker interfaces for testability
- Add NewBusinessOrchestratorWithDeps constructor for dependency injection
- Create resourceServerWrapper to adapt concrete type to interface
- Maintain backward compatibility with existing code
…succeeds

- Fix ensureExtension to return error even if transitionToFailed succeeds
- Fix handlePaymentSubmitted to return error even if transitionToFailed succeeds
- Ensures proper error propagation in payment flow
- Add TestExtractPaymentPayload with coverage for message and task extraction
- Add TestExtractPaymentRequirements with error handling tests
- Add TestExtractPaymentReceipts with multiple receipt scenarios
@0xfakeSpike 0xfakeSpike requested a review from a team as a code owner February 26, 2026 14:26
@google-cla
Copy link

google-cla bot commented Feb 26, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @0xfakeSpike, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a complete Go implementation of the x402 A2A payment protocol, focusing on an improved, testable architecture. It includes both merchant and client components, along with example applications, and features extensive test coverage. The changes enhance the protocol's robustness by addressing error handling and introducing clear interface abstractions for better maintainability and testability.

Highlights

  • Go Implementation of x402 v2 Protocol: A complete Go implementation of the x402 A2A payment protocol version 2 has been added, including both merchant and client components.
  • Improved Architecture for Testability: Key components like the BusinessOrchestrator have been refactored to support dependency injection through new interfaces (ResourceServer, ExtensionChecker), significantly enhancing testability.
  • Comprehensive Test Coverage: Extensive tests have been added for the orchestrator, payment extraction functions (payload, requirements, receipts), and utility functions, ensuring robust functionality.
  • Enhanced Error Handling: Fixes were implemented to ensure errors are properly returned even when state transitions succeed and to improve error propagation within the payment flow.
  • Example Implementations: Example merchant and client applications are included, demonstrating how to integrate and use the new Go x402 implementation.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • .gitignore
    • Updated to include Go-specific build artifacts and sensitive configuration files.
  • golang/README.md
    • Added a new README detailing the Go implementation, features, requirements, quick start guide, and project structure.
  • golang/core/business/merchant_service_interface.go
    • Defined the BusinessService interface and ServiceRequirements struct for merchant business logic integration.
  • golang/core/client/a2a_client.go
    • Implemented functions for creating an A2A client, fetching agent cards, extracting extension URIs, determining RPC endpoints, and sending messages.
  • golang/core/client/a2a_extension_header.go
    • Introduced an A2A client interceptor to add X-A2A-Extensions headers to requests.
  • golang/core/client/client.go
    • Provided a high-level client wrapper that integrates both A2A and x402 client functionalities.
  • golang/core/client/payment_handler.go
    • Implemented client-side logic to process various x402 payment states, including handling PaymentRequired and PaymentFailed.
  • golang/core/client/task_handler.go
    • Added a WaitForCompletion method to send messages and monitor task status, including payment state processing.
  • golang/core/client/x402_client.go
    • Developed an x402 client wrapper to manage network key pairs, register payment schemes (EVM, Solana), and create payment payloads.
  • golang/core/merchant/interfaces.go
    • Defined ResourceServer and ExtensionChecker interfaces to abstract x402 resource server operations and extension checking for improved testability.
  • golang/core/merchant/merchant.go
    • Implemented the Merchant struct, responsible for initializing the business orchestrator.
  • golang/core/merchant/orchestrator.go
    • Created the BusinessOrchestrator to manage the payment flow, including dependency injection for testability and ensuring x402 extension activation.
  • golang/core/merchant/orchestrator_test.go
    • Added comprehensive unit tests for the BusinessOrchestrator, covering extension checks and payment flow scenarios.
  • golang/core/merchant/payment_handler.go
    • Implemented merchant-side payment handling, including building payment requirements, verifying payments, and settling payments.
  • golang/core/merchant/resource_server.go
    • Provided functions to create and initialize the x402 resource server, registering EVM and Solana payment schemes.
  • golang/core/merchant/state_transitions.go
    • Implemented functions to manage task state transitions, such as creating tasks and transitioning to payment required, completed, or failed states.
  • golang/core/types/types.go
    • Defined NetworkConfig and NetworkKeyPair structs for managing blockchain network configurations and private keys.
  • golang/core/utils/utils.go
    • Added generic utility functions ToMap, FromMap, and ToSlice for JSON marshaling and unmarshaling.
  • golang/core/utils/utils_test.go
    • Included unit tests for the ToMap, FromMap, and ToSlice utility functions.
  • golang/core/x402/a2a_fields.go
    • Introduced utility functions to add and extract A2A-specific fields (resource, description, mimeType, outputSchema) to/from x402 payment requirements.
  • golang/core/x402/constants.go
    • Defined constants for x402 extension URI, supported networks (Base, Solana), and metadata keys, along with a network normalization function.
  • golang/core/x402/state/encode.go
    • Implemented EncodePaymentSubmission to create an A2A message for submitting payment payloads.
  • golang/core/x402/state/extract.go
    • Provided functions to extract various payment-related metadata (status, payload, requirements, receipts, original prompt) from A2A tasks and messages.
  • golang/core/x402/state/extract_test.go
    • Added unit tests for the payment state extraction functions.
  • golang/core/x402/state/record.go
    • Implemented functions to record payment state changes (required, verified, completed, failed) within A2A task messages.
  • golang/core/x402/state/set.go
    • Provided helper functions to set payment-related metadata fields in A2A messages.
  • golang/core/x402/state/types.go
    • Defined PaymentStatus enum and PaymentState struct to represent the current state of an x402 payment.
  • golang/examples/client/client_config.example.json
    • Added an example JSON configuration file for the client, including network key pairs.
  • golang/examples/client/config.go
    • Implemented logic to load client configuration from a JSON file.
  • golang/examples/client/main.go
    • Provided the main entry point for the example client application, demonstrating how to interact with a merchant.
  • golang/examples/merchant/config.go
    • Implemented logic to load merchant server configuration from a JSON file.
  • golang/examples/merchant/image_service.go
    • Created an example ImageService that uses the Gemini API to generate images, implementing the BusinessService interface.
  • golang/examples/merchant/main.go
    • Provided the main entry point for the example merchant server application.
  • golang/examples/merchant/server_config.example.json
    • Added an example JSON configuration file for the merchant server, including network configurations.
  • golang/examples/merchant/server_handler.go
    • Implemented the ServerHandler for the merchant, setting up Gin routes for agent card and RPC endpoints, and integrating the business orchestrator.
  • golang/go.mod
    • Updated Go module dependencies to include a2a-go, x402/go, and gin-gonic/gin.
  • golang/go.sum
    • Updated Go module checksums to reflect new dependencies.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a comprehensive Go implementation for the x402 A2A payment protocol, featuring core client and merchant logic, example applications, and extensive tests with a well-designed, testable architecture. However, a critical security audit revealed a high-severity broken access control vulnerability, allowing clients to bypass payment verification by manipulating message metadata, and a medium-severity prompt injection vulnerability in the example image generation service. Additionally, areas for improvement include error handling consistency, context propagation, and minor documentation and code maintainability issues.

Comment on lines +40 to +45
result, err := s.client.Models.GenerateContent(
ctx,
"gemini-2.5-flash-image",
genai.Text(prompt),
nil,
)
Copy link
Contributor

Choose a reason for hiding this comment

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

security-medium medium

The Execute function in the ImageService example passes user-provided prompts directly to the Gemini LLM without any sanitization or validation. An attacker can use prompt injection techniques to manipulate the LLM's behavior, potentially generating inappropriate content or bypassing intended service constraints, all while using the merchant's API credentials and incurring costs for the merchant.

*.pyc
*.pyo
*.pyd
.Python
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

There seems to be a typo here. It should probably be # Python (a comment) instead of .Python.

# Python

client *a2aclient.Client
}

func NewClient(merchantURL string, networkKeyPairs []types.NetworkKeyPair) (*Client, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The NewClient function uses context.Background() when creating the A2A client. In library code, it's better to accept a context.Context from the caller. This gives the user of the library control over deadlines, cancellation, and passing request-scoped values.

Suggested change
func NewClient(merchantURL string, networkKeyPairs []types.NetworkKeyPair) (*Client, error) {
func NewClient(ctx context.Context, merchantURL string, networkKeyPairs []types.NetworkKeyPair) (*Client, error) {

} else if part.InlineData != nil {
imageBytes := part.InlineData.Data
outputFilename := "./gemini_generated_image.png"
_ = os.WriteFile(outputFilename, imageBytes, 0644)
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The error returned by os.WriteFile is being ignored. While this is an example, it's good practice to handle potential errors, such as disk full or permission issues. At a minimum, the error should be logged.

			if err := os.WriteFile(outputFilename, imageBytes, 0644); err != nil {
				// Log or handle the error. For this example, we can just log it.
				fmt.Printf("Warning: failed to write image to file: %v\n", err)
			}


require (
github.com/a2aproject/a2a-go v0.3.5
github.com/coinbase/x402/go v0.0.0-20260206180803-de9f9f53b20c
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The pseudo-version for github.com/coinbase/x402/go has a year of 2026, which is highly unusual and suggests a potential issue with how the dependency was added or a typo in a commit timestamp. This should be investigated to ensure the correct and intended version of the dependency is being used.

Update client configuration documentation to use 'networkName' instead of 'network' to match the actual configuration field name.
@0xfakeSpike 0xfakeSpike marked this pull request as draft February 26, 2026 14:50
- ExtractPaymentStatus now only reads from task status, completely ignores message metadata
- Merchant orchestrator only processes payment based on task state, not client-submitted status
- Added PaymentRequired branch to handle client payment submission correctly
- Updated tests to reflect security changes

This fixes a critical security vulnerability where malicious clients could
bypass payment verification by setting x402.payment.status in message metadata
to 'payment-verified' or 'payment-completed'. Now merchant only uses task
status which is merchant-controlled.
Previously, when payment failed, if marshalling the error message failed
or if there was no message, the function would return nil, effectively
swallowing the error. This could lead to payment failures being silently
ignored.

Now the function always returns an error in the PaymentFailed case:
- First tries to marshal the full message object
- Falls back to extracting text from message parts if marshalling fails
- Returns a generic error if no message is available

This ensures payment failures are never silently ignored.
… task

Previously, when encountering an unknown payment state in a working task,
if json.Marshal failed or if there was no message, the function would
return nil, effectively swallowing the error. This could lead to silent
failures.

Now the function always returns an error when task is in working state
with unknown payment state:
- First tries to marshal the full message object
- Falls back to extracting text from message parts if marshalling fails
- Returns a generic error with payment state if no message is available

This ensures unknown payment states in working tasks are never silently
ignored and errors are properly propagated to the caller.
Previously, when payment verification failed, the task was transitioned to
a failed state but then the verification error was returned. This caused
the Execute method in the orchestrator to propagate an error, suggesting
an orchestrator failure rather than a normal business flow failure.

After successfully transitioning the task to a failed state, the function
now returns nil, nil. This indicates that the request was handled
successfully (by failing the task), allowing the orchestrator's Execute
method to complete without an error, which is consistent with how other
business logic failures are handled.
@0xfakeSpike 0xfakeSpike marked this pull request as ready for review February 26, 2026 15:33
@0xfakeSpike 0xfakeSpike reopened this Feb 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant